diff options
Diffstat (limited to 'src/client/views/collections')
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.scss | 104 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 20 | ||||
-rw-r--r-- | src/client/views/collections/CollectionPDFView.scss | 27 | ||||
-rw-r--r-- | src/client/views/collections/CollectionPDFView.tsx | 26 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.scss | 383 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 32 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.scss | 32 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 25 | ||||
-rw-r--r-- | src/client/views/collections/CollectionVideoView.scss | 40 | ||||
-rw-r--r-- | src/client/views/collections/CollectionVideoView.tsx | 86 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 9 | ||||
-rw-r--r-- | src/client/views/collections/MarqueeView.tsx | 49 | ||||
-rw-r--r-- | src/client/views/collections/PreviewCursor.tsx | 8 |
13 files changed, 556 insertions, 285 deletions
diff --git a/src/client/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss index d472cc5c4..9c7a03b52 100644 --- a/src/client/views/collections/CollectionFreeFormView.scss +++ b/src/client/views/collections/CollectionFreeFormView.scss @@ -1,29 +1,56 @@ +@import "../global_variables"; + .collectionfreeformview-container { + .collectionfreeformview > .jsx-parser { + position: absolute; + height: 100%; + width: 100%; + } - .collectionfreeformview > .jsx-parser{ - position:absolute; - height: 100%; - width: 100%; - } - - border-style: solid; - box-sizing: border-box; - position: relative; + //nested freeform views + .collectionfreeformview-container { + // background-image: linear-gradient(to right, $light-color-secondary 1px, transparent 1px), + // linear-gradient(to bottom, $light-color-secondary 1px, transparent 1px); + // background-size: 30px 30px; + } + + border: 0px solid $light-color-secondary; + border-radius: $border-radius; + box-sizing: border-box; + position: relative; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw; + .collectionfreeformview { + position: absolute; top: 0; left: 0; width: 100%; height: 100%; - overflow: hidden; - .collectionfreeformview { - position: absolute; - top: 0; - left: 0; - width:100%; - height: 100%; - } + } } .collectionfreeformview-overlay { + .collectionfreeformview > .jsx-parser { + position: absolute; + height: 100%; + } + .formattedTextBox-cont { + background: $light-color-secondary; + } + position:absolute; + border: 0px solid transparent; + border-radius: $border-radius; + overflow: hidden; + box-sizing: border-box; + top: 0; + left: 0; + width: 100%; + height: 100%; + .collectionfreeformview { .collectionfreeformview > .jsx-parser{ position:absolute; height: 100%; @@ -32,26 +59,39 @@ background:yellow; } - border-style: solid; - box-sizing: border-box; + // overflow: hidden; + // border-style: solid; + // box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; - overflow: hidden; - .collectionfreeformview { - position: absolute; - top: 0; - left: 0; - width:100%; - height: 100%; - } + } } +// selection border...? .border { - border-style: solid; - box-sizing: border-box; - width: 100%; - height: 100%; -}
\ No newline at end of file + border-style: solid; + box-sizing: border-box; + width: 98%; + height: 98%; + border-radius: $border-radius; +} + +//this is an animation for the blinking cursor! +@keyframes blink { + 0% { + opacity: 0; + } + 49% { + opacity: 0; + } + 50% { + opacity: 1; + } +} + +#prevCursor { + animation: blink 1s infinite; +} diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 3d5326552..5c0eab392 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -52,13 +52,13 @@ export class CollectionFreeFormView extends CollectionViewBase { } public getActiveDocuments = () => { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1); + var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField); let active: Document[] = []; if (lvalue && lvalue != FieldWaiting) { lvalue.Data.map(doc => { - var page = doc.GetNumber(KeyStore.Page, 0); - if (page == curPage || page == 0) { + var page = doc.GetNumber(KeyStore.Page, -1); + if (page == curPage || page == -1) { active.push(doc); } }) @@ -126,7 +126,7 @@ export class CollectionFreeFormView extends CollectionViewBase { onPointerUp = (e: PointerEvent): void => { e.stopPropagation(); - if (!this.MarqueeVisible && Math.abs(this.DownX - e.clientX) < 3 && Math.abs(this.DownY - e.clientY) < 3) { + if (Math.abs(this.DownX - e.clientX) < 4 && Math.abs(this.DownY - e.clientY) < 4) { //show preview text cursor on tap this.PreviewCursorVisible = true; //select is not already selected @@ -140,9 +140,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble && this.props.active()) { - if (e.buttons != 2 && !e.altKey && !e.metaKey && !this.MarqueeVisible) { + if (e.buttons == 1 && !e.altKey && !e.metaKey) { this.MarqueeVisible = true; - this.PreviewCursorVisible = false; } if (this.MarqueeVisible) { e.stopPropagation(); @@ -152,7 +151,6 @@ export class CollectionFreeFormView extends CollectionViewBase { let x = this.props.Document.GetNumber(KeyStore.PanX, 0); let y = this.props.Document.GetNumber(KeyStore.PanY, 0); let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - this.PreviewCursorVisible = false; this.SetPan(x - dx, y - dy); this._lastX = e.pageX; this._lastY = e.pageY; @@ -272,7 +270,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @computed get views() { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1); + var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField); if (lvalue && lvalue != FieldWaiting) { return lvalue.Data.map(doc => { @@ -343,10 +341,12 @@ export class CollectionFreeFormView extends CollectionViewBase { ref={this._canvasRef}> {this.backgroundView} <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} /> - <PreviewCursor container={this} addLiveTextDocuemnt={this.addLiveTextBox} getTransform={this.getTransform} /> + <PreviewCursor container={this} addLiveTextDocument={this.addLiveTextBox} getTransform={this.getTransform} /> {this.views} </div> - <MarqueeView container={this} activeDocuemnts={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} getMarqueeTransform={this.getMarqueeTransform} getTransform={this.getTransform} /> + <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} + addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} + getMarqueeTransform={this.getMarqueeTransform} getTransform={this.getTransform} /> {this.overlayView} </div> ); diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss new file mode 100644 index 000000000..0144625c1 --- /dev/null +++ b/src/client/views/collections/CollectionPDFView.scss @@ -0,0 +1,27 @@ +.collectionPdfView-buttonTray { + top : 25px; + left : 20px; + position: relative; + transform-origin: left top; + position: absolute; +} +.collectionPdfView-cont{ + width: 100%; + height: 100%; + position: absolute; + +} +.collectionPdfView-backward { + color : white; + top :0px; + left : 0px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); +} +.collectionPdfView-forward { + color : white; + top :0px; + left : 35px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); +}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index f22c07060..124d82c8b 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -1,10 +1,11 @@ -import { action, computed } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; +import "./CollectionPDFView.scss" import React = require("react"); import { FieldId } from "../../../fields/Field"; @@ -18,22 +19,23 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> { isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; } - public SelectedDocs: FieldId[] = [] - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0; + private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } + private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } + @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1; + @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; - @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); } - @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } - @computed private get uIButtons() { + private get uIButtons() { + let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); return ( - <div className="pdfBox-buttonTray" key="tray"> - <button className="pdfButton" onClick={this.onPageBack}>{"<"}</button> - <button className="pdfButton" onClick={this.onPageForward}>{">"}</button> + <div className="collectionPdfView-buttonTray" key="tray" style={{ transform: `scale(${scaling}, ${scaling})` }}> + <button className="collectionPdfView-backward" onClick={this.onPageBack}>{"<"}</button> + <button className="collectionPdfView-forward" onClick={this.onPageForward}>{">"}</button> </div>); } // "inherited" CollectionView API starts here... - + @observable + public SelectedDocs: FieldId[] = [] public active: () => boolean = () => CollectionView.Active(this); addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } @@ -49,7 +51,7 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> { get subView(): any { return CollectionView.SubView(this); } render() { - return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}> + return (<div className="collectionPdfView-cont" onContextMenu={this.specificContextMenu}> {this.subView} {this.props.isSelected() ? this.uIButtons : (null)} </div>) diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index d40e6d314..0d615dc01 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,185 +1,162 @@ - +@import "../global_variables"; .collectionSchemaView-container { - border-style: solid; + border: 1px solid $intermediate-color; + border-radius: $border-radius; + box-sizing: border-box; + position: absolute; + width: 100%; + height: 100%; + overflow: hidden; + +.collectionSchemaView-content { + position: absolute; + height:100%; + width:100%; + overflow:auto; +} + .collectionSchemaView-previewRegion { + position: relative; + background: $light-color; + float: left; + height: 100%; + } + .collectionSchemaView-previewHandle { + position: absolute; + height: 37px; + width: 20px; + z-index: 20; + right: 0; + top: 0; + background: $main-accent; + } + .collectionSchemaView-dividerDragger { + position: relative; box-sizing: border-box; + border-left: 1px solid $intermediate-color; + border-right: 1px solid $intermediate-color; + float: left; + height: 100%; + } + .collectionSchemaView-tableContainer { + position: relative; + float: left; + height: 100%; + } + + .ReactTable { position: absolute; + // display: inline-block; + // overflow: auto; width: 100%; height: 100%; - .collectionSchemaView-previewRegion { - position: relative; - background: black; - float: left; - height: 100%; - } - .collectionSchemaView-previewHandle { - position: absolute; - height: 37px; - width: 20px; - z-index: 20; - right: 0; - top: 0; - background: Black ; - } - .collectionSchemaView-dividerDragger{ - position: relative; - background: black; - float: left; - height: 100%; - } - .collectionSchemaView-tableContainer { + background: $light-color; + box-sizing: border-box; + border: none !important; + .rt-table { + overflow-y: auto; + overflow-x: auto; + height: 100%; + display: -webkit-inline-box; + direction: ltr; + // direction:rtl; + // display:block; + } + .rt-tbody { + //direction: ltr; + direction: rtl; + } + .rt-tr-group { + direction: ltr; + max-height: 44px; + } + .rt-td { + border-width: 1px; + border-right-color: $intermediate-color; + .imageBox-cont { position: relative; - float: left; - height: 100%; - } - - .ReactTable { - position: absolute; - // display: inline-block; - // overflow: auto; - width: 100%; + max-height: 100%; + } + .imageBox-cont img { + object-fit: contain; + max-width: 100%; height: 100%; - background: white; - box-sizing: border-box; - .rt-table { - overflow-y: auto; - overflow-x: auto; - height: 100%; - - display: -webkit-inline-box; - direction: ltr; - // direction:rtl; - // display:block; - } - .rt-tbody { - //direction: ltr; - direction: rtl; - } - .rt-tr-group { - direction: ltr; - max-height: 44px; - } - .rt-td { - border-width: 1; - border-right-color: #aaa; - .imageBox-cont { - position:relative; - max-height:100%; - } - .imageBox-cont img { - object-fit: contain; - max-width: 100%; - height: 100% - } - } - .rt-tr-group { - border-width: 1; - border-bottom-color: #aaa - } - } - .ReactTable .rt-thead.-header { - background:grey; - } - .ReactTable .rt-th, .ReactTable .rt-td { - max-height: 44; - padding: 3px 7px; - } - .ReactTable .rt-tbody .rt-tr-group:last-child { - border-bottom: grey; - border-bottom-style: solid; - border-bottom-width: 1; - } - .documentView-node:first-child { - background: grey; - .imageBox-cont img { - object-fit: contain; - } - } + } + .videobox-cont { + object-fit: contain; + width:auto; + height: 100%; + } + } + } + .ReactTable .rt-thead.-header { + background: $intermediate-color; + color: $light-color; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 12px; + height: 30px; + padding-top: 4px; + } + .ReactTable .rt-th, + .ReactTable .rt-td { + max-height: 44; + padding: 3px 7px; + font-size: 13px; + text-align: center; + } + .ReactTable .rt-tbody .rt-tr-group:last-child { + border-bottom: $intermediate-color; + border-bottom-style: solid; + border-bottom-width: 1; + } + .documentView-node:first-child { + background: $light-color; + .imageBox-cont img { + object-fit: contain; + } + } } .Resizer { - box-sizing: border-box; - background: #000; - opacity: 0.5; - z-index: 1; - background-clip: padding-box; - &.horizontal { - height: 11px; - margin: -5px 0; - border-top: 5px solid rgba(255, 255, 255, 0); - border-bottom: 5px solid rgba(255, 255, 255, 0); - cursor: row-resize; - width: 100%; - &:hover { - border-top: 5px solid rgba(0, 0, 0, 0.5); - border-bottom: 5px solid rgba(0, 0, 0, 0.5); - } - } - &.vertical { - width: 11px; - margin: 0 -5px; - border-left: 5px solid rgba(255, 255, 255, 0); - border-right: 5px solid rgba(255, 255, 255, 0); - cursor: col-resize; - &:hover { - border-left: 5px solid rgba(0, 0, 0, 0.5); - border-right: 5px solid rgba(0, 0, 0, 0.5); - } - } + box-sizing: border-box; + background: #000; + opacity: 0.5; + z-index: 1; + background-clip: padding-box; + &.horizontal { + height: 11px; + margin: -5px 0; + border-top: 5px solid rgba(255, 255, 255, 0); + border-bottom: 5px solid rgba(255, 255, 255, 0); + cursor: row-resize; + width: 100%; &:hover { - -webkit-transition: all 2s ease; - transition: all 2s ease; - } + border-top: 5px solid rgba(0, 0, 0, 0.5); + border-bottom: 5px solid rgba(0, 0, 0, 0.5); + } + } + &.vertical { + width: 11px; + margin: 0 -5px; + border-left: 5px solid rgba(255, 255, 255, 0); + border-right: 5px solid rgba(255, 255, 255, 0); + cursor: col-resize; + &:hover { + border-left: 5px solid rgba(0, 0, 0, 0.5); + border-right: 5px solid rgba(0, 0, 0, 0.5); + } + } + &:hover { + -webkit-transition: all 2s ease; + transition: all 2s ease; + } } .vertical { - section { - width: 100vh; - height: 100vh; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - } - header { - padding: 1rem; - background: #eee; - } - footer { - padding: 1rem; - background: #eee; - } -} - -.horizontal { - section { - width: 100vh; - height: 100vh; - display: flex; - flex-direction: column; - } - header { - padding: 1rem; - background: #eee; - } - footer { - padding: 1rem; - background: #eee; - } -} - -.parent { - width: 100%; - height: 100%; - -webkit-box-flex: 1; - -webkit-flex: 1; - -ms-flex: 1; - flex: 1; + section { + width: 100vh; + height: 100vh; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -189,19 +166,71 @@ -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; + } + header { + padding: 1rem; + background: #eee; + } + footer { + padding: 1rem; + background: #eee; + } +} + +.horizontal { + section { + width: 100vh; + height: 100vh; + display: flex; + flex-direction: column; + } + header { + padding: 1rem; + background: #eee; + } + footer { + padding: 1rem; + background: #eee; + } +} + +.parent { + width: 100%; + height: 100%; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } .header { - background: #aaa; - height: 3rem; - line-height: 3rem; + background: #aaa; + height: 3rem; + line-height: 3rem; } .wrapper { - background: #ffa; - margin: 5rem; - -webkit-box-flex: 1; - -webkit-flex: 1; - -ms-flex: 1; - flex: 1; -}
\ No newline at end of file + background: #ffa; + margin: 5rem; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.-even { + background: $light-color !important; +} + +.-odd { + background: $light-color-secondary !important; +} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 04f017378..8c1aeef2c 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,5 +1,5 @@ import React = require("react") -import { action, observable } from "mobx"; +import { action, observable, computed } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; @@ -24,14 +24,14 @@ import { setupDrag } from "../../util/DragManager"; @observer export class CollectionSchemaView extends CollectionViewBase { private _mainCont = React.createRef<HTMLDivElement>(); - private DIVIDER_WIDTH = 5; + private DIVIDER_WIDTH = 4; @observable _contentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ContentScaling prop of the DocumentView @observable _dividerX = 0; @observable _panelWidth = 0; @observable _panelHeight = 0; @observable _selectedIndex = 0; - @observable _splitPercentage: number = 50; + @computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0); } renderCell = (rowProps: CellInfo) => { let props: FieldViewProps = { @@ -49,7 +49,7 @@ export class CollectionSchemaView extends CollectionViewBase { let reference = React.createRef<HTMLDivElement>(); let onItemDown = setupDrag(reference, () => props.doc); return ( - <div onPointerDown={onItemDown} key={props.doc.Id} ref={reference}> + <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "36px" }} key={props.doc.Id} ref={reference}> <EditableView contents={contents} height={36} GetValue={() => { let field = props.doc.Get(props.fieldKey); @@ -89,7 +89,8 @@ export class CollectionSchemaView extends CollectionViewBase { return { onClick: action((e: React.MouseEvent, handleOriginal: Function) => { that._selectedIndex = rowInfo.index; - this._splitPercentage += 0.05; // bcz - ugh - needed to force Measure to do its thing and call onResize + // bcz - ugh - needed to force Measure to do its thing and call onResize + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage - 0.05) if (handleOriginal) { handleOriginal() @@ -106,18 +107,18 @@ export class CollectionSchemaView extends CollectionViewBase { @action onDividerMove = (e: PointerEvent): void => { let nativeWidth = this._mainCont.current!.getBoundingClientRect(); - this._splitPercentage = Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100); + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100)); } @action onDividerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onDividerMove); document.removeEventListener('pointerup', this.onDividerUp); - if (this._startSplitPercent == this._splitPercentage) { - this._splitPercentage = this._splitPercentage == 1 ? 66 : 100; + if (this._startSplitPercent == this.splitPercentage) { + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0); } } onDividerDown = (e: React.PointerEvent) => { - this._startSplitPercent = this._splitPercentage; + this._startSplitPercent = this.splitPercentage; e.stopPropagation(); e.preventDefault(); document.addEventListener("pointermove", this.onDividerMove); @@ -134,12 +135,12 @@ export class CollectionSchemaView extends CollectionViewBase { e.preventDefault(); document.removeEventListener("pointermove", this.onExpanderMove); document.removeEventListener('pointerup', this.onExpanderUp); - if (this._startSplitPercent == this._splitPercentage) { - this._splitPercentage = this._splitPercentage == 100 ? 66 : 100; + if (this._startSplitPercent == this.splitPercentage) { + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0); } } onExpanderDown = (e: React.PointerEvent) => { - this._startSplitPercent = this._splitPercentage; + this._startSplitPercent = this.splitPercentage; e.stopPropagation(); e.preventDefault(); document.addEventListener("pointermove", this.onExpanderMove); @@ -203,7 +204,7 @@ export class CollectionSchemaView extends CollectionViewBase { ) let previewHandle = !this.props.active() ? (null) : ( <div className="collectionSchemaView-previewHandle" onPointerDown={this.onExpanderDown} />); - let dividerDragger = this._splitPercentage == 100 ? (null) : + let dividerDragger = this.splitPercentage == 0 ? (null) : <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} /> return ( <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} ref={this._mainCont} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} > @@ -213,7 +214,8 @@ export class CollectionSchemaView extends CollectionViewBase { this._panelHeight = r.entry.height; })}> {({ measureRef }) => - <div ref={measureRef} className="collectionSchemaView-tableContainer" style={{ width: `${this._splitPercentage}%` }}> + <div ref={measureRef} className="collectionSchemaView-tableContainer" + style={{ width: `calc(100% - ${this.splitPercentage}%)` }}> <ReactTable data={children} pageSize={children.length} @@ -235,7 +237,7 @@ export class CollectionSchemaView extends CollectionViewBase { } </Measure> {dividerDragger} - <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${100 - this._splitPercentage}% - ${this.DIVIDER_WIDTH}px)` }}> + <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0)}% - ${this.DIVIDER_WIDTH}px)` }}> {content} </div> {previewHandle} diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index f8d580a7b..fa0f1c761 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,16 +1,25 @@ +@import "../global_variables"; #body { padding: 20px; - background: #bbbbbb; + background: $light-color-secondary; + font-size: 13px; + overflow: scroll; } ul { list-style: none; + padding-left: 20px; } li { margin: 5px 0; } +.collection-child { + margin-top: 10px; + margin-bottom: 10px; +} + .no-indent { padding-left: 0; } @@ -18,10 +27,17 @@ li { .bullet { width: 1.5em; display: inline-block; + color: $intermediate-color; +} + +.coll-title { + font-size: 24px; + margin-bottom: 20px; } .collectionTreeView-dropTarget { - border-style: solid; + border: 0px solid transparent; + border-radius: $border-radius; box-sizing: border-box; height: 100%; } @@ -30,8 +46,16 @@ li { display: inline-table; } +.docContainer:hover { + .delete-button { + display: inline; + } +} + .delete-button { - color: #999999; + color: $intermediate-color; float: right; - margin-left: 1em; + margin-left: 15px; + margin-top: 3px; + display: none; }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8b06d9ac4..80fc89712 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -12,6 +12,10 @@ import { setupDrag } from "../../util/DragManager"; import { FieldWaiting } from "../../../fields/Field"; import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTrashAlt, faCaretRight, faCaretDown } from '@fortawesome/free-solid-svg-icons'; + export interface TreeViewProps { document: Document; deleteDoc: (doc: Document) => void; @@ -23,6 +27,10 @@ export enum BulletType { List } +library.add(faTrashAlt); +library.add(faCaretDown); +library.add(faCaretRight); + @observer /** * Component that takes in a document prop and a boolean whether it's collapsed or not. @@ -50,11 +58,11 @@ class TreeView extends React.Component<TreeViewProps> { switch (type) { case BulletType.Collapsed: - return <div className="bullet" onClick={onClicked}>▶</div> + return <div className="bullet" onClick={onClicked}><FontAwesomeIcon icon="caret-right" /></div> case BulletType.Collapsible: - return <div className="bullet" onClick={onClicked}>▼</div> + return <div className="bullet" onClick={onClicked}><FontAwesomeIcon icon="caret-down" /></div> case BulletType.List: - return <div className="bullet">—</div> + return <div className="bullet"></div> } } @@ -79,7 +87,7 @@ class TreeView extends React.Component<TreeViewProps> { this.props.document.SetData(KeyStore.Title, value, TextField); return true; }} /> - <div className="delete-button" onClick={this.delete}>x</div> + <div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div> </div > } @@ -101,7 +109,7 @@ class TreeView extends React.Component<TreeViewProps> { <TreeView document={value} deleteDoc={this.remove} />) ) subView = - <li key={this.props.document.Id} > + <li className="collection-child" key={this.props.document.Id} > {this.renderBullet(BulletType.Collapsible)} {titleElement} <ul key={this.props.document.Id}> @@ -109,7 +117,7 @@ class TreeView extends React.Component<TreeViewProps> { </ul> </li> } else { - subView = <li key={this.props.document.Id}> + subView = <li className="collection-child" key={this.props.document.Id}> {this.renderBullet(BulletType.Collapsed)} {titleElement} </li> @@ -157,7 +165,7 @@ export class CollectionTreeView extends CollectionViewBase { return ( <div id="body" className="collectionTreeView-dropTarget" onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}> - <h3> + <div className="coll-title"> <EditableView contents={titleStr} height={72} GetValue={() => { return this.props.Document.Title; @@ -165,7 +173,8 @@ export class CollectionTreeView extends CollectionViewBase { this.props.Document.SetData(KeyStore.Title, value, TextField); return true; }} /> - </h3> + </div> + <hr /> <ul className="no-indent"> {childrenElement} </ul> diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss new file mode 100644 index 000000000..cbb981b13 --- /dev/null +++ b/src/client/views/collections/CollectionVideoView.scss @@ -0,0 +1,40 @@ + +.collectionVideoView-cont{ + width: 100%; + height: 100%; + position: absolute; + +} +.collectionVideoView-time{ + color : white; + top :25px; + left : 25px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); + transform-origin: left top; +} +.collectionVideoView-play { + width: 25px; + height: 20px; + bottom: 25px; + left : 25px; + position: absolute; + color : white; + background-color: rgba(50, 50, 50, 0.2); + border-radius: 4px; + text-align: center; + transform-origin: left bottom; +} +.collectionVideoView-full { + width: 25px; + height: 20px; + bottom: 25px; + right : 25px; + position: absolute; + color : white; + background-color: rgba(50, 50, 50, 0.2); + border-radius: 4px; + text-align: center; + transform-origin: right bottom; + +}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index a6471f53c..b64ef3c07 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; @@ -7,6 +7,7 @@ import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; +import "./CollectionVideoView.scss" @observer @@ -18,14 +19,29 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; } - public SelectedDocs: FieldId[] = [] - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0; + private _mainCont = React.createRef<HTMLDivElement>(); + + private get uIButtons() { + let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); + return ([ + <div className="collectionVideoView-time" key="time" onPointerDown={this.onResetDown} style={{ transform: `scale(${scaling}, ${scaling})` }}> + <span>{"" + Math.round(this.ctime)}</span> + <span style={{ fontSize: 8 }}>{" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)}</span> + </div>, + <div className="collectionVideoView-play" key="play" onPointerDown={this.onPlayDown} style={{ transform: `scale(${scaling}, ${scaling})` }}> + {this.playing ? "\"" : ">"} + </div>, + <div className="collectionVideoView-full" key="full" onPointerDown={this.onFullDown} style={{ transform: `scale(${scaling}, ${scaling})` }}> + F + </div> + ]); + } + - @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); } - @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } // "inherited" CollectionView API starts here... + @observable + public SelectedDocs: FieldId[] = [] public active: () => boolean = () => CollectionView.Active(this); addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } @@ -40,11 +56,63 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; } get subView(): any { return CollectionView.SubView(this); } + componentDidMount() { + this.updateTimecode(); + } + + get player(): HTMLVideoElement | undefined { + return this._mainCont.current ? this._mainCont.current.getElementsByTagName("video")[0] : undefined; + } + + @action + updateTimecode = () => { + if (this.player) { + this.ctime = this.player.currentTime; + this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this.ctime)); + } + setTimeout(() => this.updateTimecode(), 100) + } + + + @observable + ctime: number = 0 + @observable + playing: boolean = false; + + @action + onPlayDown = () => { + if (this.player) { + if (this.player.paused) { + this.player.play(); + this.playing = true; + } else { + this.player.pause(); + this.playing = false; + } + } + } + @action + onFullDown = (e: React.PointerEvent) => { + if (this.player) { + this.player.requestFullscreen(); + e.stopPropagation(); + e.preventDefault(); + } + } + + @action + onResetDown = () => { + if (this.player) { + this.player.pause(); + this.player.currentTime = 0; + } + + } + render() { - return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}> - {/* <video controls className="videobox-cont"> */} + return (<div className="collectionVideoView-cont" ref={this._mainCont} onContextMenu={this.specificContextMenu}> {this.subView} - {/* </video> */} + {this.uIButtons} </div>) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 17a0fbd23..d9b2722a6 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -22,20 +22,19 @@ export enum CollectionViewType { Tree } -export const COLLECTION_BORDER_WIDTH = 2; +export const COLLECTION_BORDER_WIDTH = 1; @observer export class CollectionView extends React.Component<CollectionViewProps> { - @observable - public SelectedDocs: FieldId[] = []; - public static LayoutString(fieldKey: string = "DataKey") { return `<${CollectionView.name} Document={Document} ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; } + @observable + public SelectedDocs: FieldId[] = []; public active: () => boolean = () => CollectionView.Active(this); addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } @@ -50,7 +49,7 @@ export class CollectionView extends React.Component<CollectionViewProps> { @action public static AddDocument(props: CollectionViewProps, doc: Document) { - doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, 0)); + doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1)); if (props.Document.Get(props.fieldKey) instanceof Field) { //TODO This won't create the field if it doesn't already exist const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>()) diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx index d9e4df1e9..65aaa837f 100644 --- a/src/client/views/collections/MarqueeView.tsx +++ b/src/client/views/collections/MarqueeView.tsx @@ -3,21 +3,22 @@ import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting, Opt } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; -import { ListField } from "../../../fields/ListField"; import { Documents } from "../../documents/Documents"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); - +import { InkField, StrokeData } from "../../../fields/InkField"; +import { Utils } from "../../../Utils"; +import { InkingCanvas } from "../InkingCanvas"; interface MarqueeViewProps { getMarqueeTransform: () => Transform; getTransform: () => Transform; container: CollectionFreeFormView; addDocument: (doc: Document) => void; - activeDocuemnts: () => Document[]; + activeDocuments: () => Document[]; selectDocuments: (docs: Document[]) => void; removeDocument: (doc: Document) => boolean; } @@ -92,31 +93,59 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key == "Backspace") { + if (e.key == "Backspace" || e.key == "Delete") { this.marqueeSelect().map(d => this.props.removeDocument(d)); + this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField); this.cleanupInteractions(); } if (e.key == "c") { let bounds = this.Bounds; - let selected = this.marqueeSelect().map(m => m); - this.marqueeSelect().map(d => this.props.removeDocument(d)); - //setTimeout(() => { - this.props.addDocument(Documents.FreeformDocument(selected.map(d => { + let selected = this.marqueeSelect().map(d => { + this.props.removeDocument(d); d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2); d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2); d.SetNumber(KeyStore.Page, 0); d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0)); return d; - }), { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, height: bounds.height, title: "a nested collection" })); + }); + let liftedInk = this.marqueeInkSelect(true); + this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField); + //setTimeout(() => { + this.props.addDocument(Documents.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, backgroundColor: "Transparent", height: bounds.height, ink: liftedInk, title: "a nested collection" })); // }, 100); this.cleanupInteractions(); } } + marqueeInkSelect(select: boolean) { + let selRect = this.Bounds; + let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin. + let centerShiftY = 0 - (selRect.top + selRect.height / 2); + let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); + if (ink && ink != FieldWaiting) { + let idata = new Map(); + ink.Data.forEach((value: StrokeData, key: string, map: any) => { + let inside = InkingCanvas.IntersectStrokeRect(value, selRect); + if (inside && select) { + idata.set(key, + { + pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }), + color: value.color, + width: value.width, + tool: value.tool, + page: -1 + }); + } else if (!inside && !select) { + idata.set(key, value); + } + }) + return idata; + } + } marqueeSelect() { let selRect = this.Bounds; let selection: Document[] = []; - this.props.activeDocuemnts().map(doc => { + this.props.activeDocuments().map(doc => { var x = doc.GetNumber(KeyStore.X, 0); var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.GetNumber(KeyStore.Width, 0); diff --git a/src/client/views/collections/PreviewCursor.tsx b/src/client/views/collections/PreviewCursor.tsx index ab68fbc46..a1411250a 100644 --- a/src/client/views/collections/PreviewCursor.tsx +++ b/src/client/views/collections/PreviewCursor.tsx @@ -16,7 +16,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; export interface PreviewCursorProps { getTransform: () => Transform; container: CollectionFreeFormView; - addLiveTextDocuemnt: (doc: Document) => void; + addLiveTextDocument: (doc: Document) => void; } @observer @@ -57,11 +57,13 @@ export class PreviewCursor extends React.Component<PreviewCursorProps> { @action onKeyPress = (e: KeyboardEvent) => { //if not these keys, make a textbox if preview cursor is active! - if (!e.ctrlKey && !e.altKey) { + if (!e.ctrlKey && !e.altKey && !e.defaultPrevented) { //make textbox and add it to this collection let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY); let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "new" }); - this.props.addLiveTextDocuemnt(newBox); + this.props.addLiveTextDocument(newBox); + e.stopPropagation(); + e.preventDefault(); } } |