aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx15
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.scss214
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx130
4 files changed, 244 insertions, 116 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dabbf9591..dc649ec4e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -235,6 +235,7 @@ export class DocumentOptions {
dataViz_pie?: string;
dataViz_histogram?: string;
dataViz?: string;
+ dataViz_savedTemplates?: LISTt;
layout?: string | Doc; // default layout string or template document
layout_isSvg?: BOOLt = new BoolInfo('whether document decorations and other selections should handle pointerEvents for svg content or use doc bounding box');
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 765642891..e943dd2e3 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -33,12 +33,14 @@ import { LineChart } from './components/LineChart';
import { PieChart } from './components/PieChart';
import { TableBox } from './components/TableBox';
import { LinkManager } from '../../../util/LinkManager';
-import { DataVizTemplateInfo, DocCreatorMenu, LayoutType } from './DocCreatorMenu';
+import { DataVizTemplateInfo, DataVizTemplateLayout, DocCreatorMenu, LayoutType } from './DocCreatorMenu';
import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { PrefetchProxy } from '../../../../fields/Proxy';
import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols';
import { template } from 'lodash';
import { data } from 'jquery';
+import { listSpec } from '../../../../fields/Schema';
+import { ObjectField } from '../../../../fields/ObjectField';
export enum DataVizView {
TABLE = 'table',
@@ -532,14 +534,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
}
- // applyImagesTo = (doc: Doc, cols: string[]) => {
- // const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]);
- // const imageFields = childDocs.filter(doc => doc.type === 'image');
- // const imageToKey: Map<Doc, string> = new Map();
- // imageFields.forEach(img => cols.forEach(col => {if (img[col]) imageToKey.set(img, col)}));
-
- // imageFields.forEach(doc => doc['data'] = String(doc[String(imageToKey.get(doc))]).replace(/"/g, ''));
-
+ // @action addSavedLayout = (layout: DataVizTemplateLayout) => {
+ // const saved = Cast(this.layoutDoc.dataViz_savedTemplates, listSpec('RefField'));
+
// }
@action
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
index 0fc85ba5d..d18f75545 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
@@ -68,6 +68,13 @@
height: 0;
width: 50px;
}
+
+ &.preview-toggle {
+ margin: 0px;
+ border-top-left-radius: 0px;
+ border-bottom-left-radius: 0px;
+ border-left: 0px;
+ }
}
.docCreatorMenu-top-buttons-container {
@@ -168,16 +175,44 @@
height: 25px;
}
+.docCreatorMenu-general-options-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 0px;
+ padding: 0px;
+ gap: 5px;
+}
+
+.docCreatorMenu-save-layout-button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 40px;
+ height: 40px;
+ background-color: rgb(99, 148, 238);
+ border: 2px solid rgb(80, 107, 152);
+ border-radius: 5px;
+ margin-bottom: 20px;
+ font-size: 25px;
+
+ &:hover{
+ background-color: rgb(59, 128, 255);
+ border: 2px solid rgb(53, 80, 127);
+ }
+}
+
.docCreatorMenu-create-docs-button {
- width: 80px;
+ width: 40px;
height: 40px;
background-color: rgb(176, 229, 149);
- border-radius: 5px;
border: 2px solid rgb(126, 219, 80);
+ border-radius: 5px;
padding: 0px;
- font-size: 16px;
- color: black;
+ font-size: 25px;
+ color: white;
flex: 0 0 auto;
+ margin-bottom: 20px; //remove later !!!
&:hover {
background-color: rgb(129, 223, 83);
@@ -185,6 +220,13 @@
}
}
+.docCreatorMenu-option-divider {
+ border-top: 1px solid rgb(180, 180, 180);
+ width: 225px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
//------------------------------------------------------------------------------------------------------------------------------------------
//DocCreatorMenu templates preview CSS
//--------------------------------------------------------------------------------------------------------------------------------------------
@@ -202,29 +244,32 @@
height: calc(100% - 30px);
border: 1px solid rgb(180, 180, 180);
border-radius: 5px;
+}
- .docCreatorMenu-preview-window {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 125px;
- height: 125px;
- margin-top: 10px;
- margin-left: 10px;
- border: 1px solid rgb(163, 163, 163);
- border-radius: 5px;
- box-shadow: 5px 5px rgb(29, 29, 31);
+.docCreatorMenu-preview-window {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 125px;
+ height: 125px;
+ margin-top: 10px;
+ margin-left: 10px;
+ border: 1px solid rgb(163, 163, 163);
+ border-radius: 5px;
+ box-shadow: 5px 5px rgb(29, 29, 31);
- &:hover{
- background-color: rgb(72, 72, 73);
- }
+ &:hover{
+ background-color: rgb(72, 72, 73);
+ }
- .docCreatorMenu-preview-image{
- width: 105px;
- height: 105px;
- border-radius: 5px;
- }
+ .docCreatorMenu-preview-image{
+ width: 105px;
+ height: 105px;
+ border-radius: 5px;
+ }
+ &.empty {
+ font-size: 35px;
}
}
@@ -254,6 +299,8 @@
background: whitesmoke;
background-color: rgb(34, 34, 37);
border-radius: 5px;
+ border-top-right-radius: 0px;
+ border-bottom-right-radius: 0px;
border: 1px solid rgb(180, 180, 180);
padding: 0px;
font-size: 12px;
@@ -412,75 +459,80 @@
}
}
+}
- .docCreatorMenu-layout-preview-window-wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 85%;
- height: auto;
- position: relative;
- padding: 0px;
+.docCreatorMenu-layout-preview-window-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 85%;
+ height: auto;
+ position: relative;
+ padding: 0px;
- &:hover .docCreatorMenu-zoom-button-container {
- display: block;
- }
+ &:hover .docCreatorMenu-zoom-button-container {
+ display: block;
+ }
- .docCreatorMenu-layout-preview-window {
- padding: 5px;
- flex: 0 0 auto;
- overflow: scroll;
- display: grid;
- width: auto;
- height: auto;
- max-width: 240;
- max-height: 240;
- border: 1px solid rgb(180, 180, 180);
- border-radius: 5px;
- background-color: rgb(34, 34, 37);
- -ms-overflow-style: none;
- scrollbar-width: none;
-
- .docCreatorMenu-layout-preview-item {
- display: flex;
- justify-content: center;
- align-items: center;
- border-radius: 3px;
- border: solid 1px lightblue;
-
- &:hover {
- border: solid 2px rgb(68, 153, 233);
- z-index: 2;
- }
- }
+ .docCreatorMenu-layout-preview-window {
+ padding: 5px;
+ flex: 0 0 auto;
+ overflow: scroll;
+ display: grid;
+ width: auto;
+ height: auto;
+ max-width: 240;
+ max-height: 240;
+ border: 1px solid rgb(180, 180, 180);
+ border-radius: 5px;
+ background-color: rgb(34, 34, 37);
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+
+ &.small {
+ max-width: 100;
+ max-height: 100;
}
- .docCreatorMenu-zoom-button-container {
- position: absolute;
- top: 0px;
+ .docCreatorMenu-layout-preview-item {
display: flex;
justify-content: center;
align-items: center;
- display: none;
- z-index: 999;
- }
-
- .docCreatorMenu-zoom-button{
- width: 15px;
- height: 15px;
- background: whitesmoke;
- background-color: rgb(34, 34, 37);
border-radius: 3px;
- border: 1px solid rgb(180, 180, 180);
- padding: 0px;
- font-size: 10px;
- z-index: 6;
- margin-left: 0px;
- margin-top: 0px;
- margin-right: 0px; //225px
- margin-bottom: 0px;
+ border: solid 1px lightblue;
+
+ &:hover {
+ border: solid 2px rgb(68, 153, 233);
+ z-index: 2;
+ }
}
}
+
+ .docCreatorMenu-zoom-button-container {
+ position: absolute;
+ top: 0px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ display: none;
+ z-index: 999;
+ }
+
+ .docCreatorMenu-zoom-button{
+ width: 15px;
+ height: 15px;
+ background: whitesmoke;
+ background-color: rgb(34, 34, 37);
+ border-radius: 3px;
+ border: 1px solid rgb(180, 180, 180);
+ padding: 0px;
+ font-size: 10px;
+ z-index: 6;
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 0px; //225px
+ margin-bottom: 0px;
+ }
}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 67999fc39..fdf623150 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -40,6 +40,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
@observable _layout: {type: LayoutType, yMargin: number, xMargin: number, columns?: number, repeat: number} = {type: LayoutType.Grid, yMargin: 0, xMargin: 0, repeat: 0};
@observable _layoutPreview: boolean = true;
@observable _layoutPreviewScale: number = 1;
+ @observable _savedLayouts: DataVizTemplateLayout[] = [];
@observable _pageX: number = 0;
@observable _pageY: number = 0;
@@ -193,6 +194,20 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
}
}
+ @action updateSelectedSavedLayout = (layout: DataVizTemplateLayout) => {
+ this._layout.xMargin = layout.layout.xMargin;
+ this._layout.yMargin = layout.layout.yMargin;
+ this._layout.type = layout.layout.type;
+ this._layout.columns = layout.columns;
+ }
+
+ isSelectedLayout = (layout: DataVizTemplateLayout) => {
+ return this._layout.xMargin === layout.layout.xMargin
+ && this._layout.yMargin === layout.layout.yMargin
+ && this._layout.type === layout.layout.type
+ && this._layout.columns === layout.columns;
+ }
+
get templatesPreviewContents(){
const renderedTemplates: Doc[] = [];
return (
@@ -203,13 +218,35 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
return (<div
className='docCreatorMenu-preview-window'
style={{
- background: this._selectedTemplate === info.doc ? Colors.MEDIUM_BLUE : '',
+ border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
}}
onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
<img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
</div>
)})}
+ <div className='docCreatorMenu-preview-window empty'>
+ <FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
+ </div>
+ </div>
+ );
+ }
+
+ get savedLayoutsPreviewContents(){
+ return (
+ <div className='docCreatorMenu-preview-container'>
+ {this._savedLayouts.map((layout, index) =>
+ <div
+ className='docCreatorMenu-preview-window'
+ style={{
+ border: this.isSelectedLayout(layout) ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+ boxShadow: this.isSelectedLayout(layout) ? `0 0 15px rgba(68, 118, 247, .8)` : ''
+ }}
+ onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedSavedLayout(layout)))}
+ >
+ {this.layoutPreviewContents(87, layout, false, true, index)}
+ </div>
+ )}
</div>
);
}
@@ -259,20 +296,23 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
}
}
+ layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, zoomOption: boolean = true, small: boolean = false, id?: number) => {
+ const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate;
+ if (!doc) return;
+ const layout = altLayout ? altLayout.layout : this._layout;
- get layoutPreviewContents() {
- const docWidth = Number(this._selectedTemplate?._width);
- const docHeight = Number(this._selectedTemplate?._height);
- const horizontalSpan: number = (docWidth + this._layout.xMargin) * this.columnsCount - this._layout.xMargin;
- const verticalSpan: number = (docHeight + this._layout.yMargin) * this.rowsCount - this._layout.yMargin;
+ const docWidth: number = Number(doc._width);
+ const docHeight: number = Number(doc._height);
+ const horizontalSpan: number = (docWidth + layout.xMargin) * (altLayout ? altLayout.columns : this.columnsCount) - layout.xMargin;;
+ const verticalSpan: number = (docHeight + layout.yMargin) * (altLayout ? altLayout.rows : this.rowsCount) - layout.yMargin;
const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
- const scaledDown = (input: number) => {return input / (largerSpan / 225 * this._layoutPreviewScale)}
+ const scaledDown = (input: number) => {return input / (largerSpan / outerSpan * this._layoutPreviewScale)}
const fontSize = Math.min(scaledDown(docWidth / 3), scaledDown(docHeight / 3));
return (
- <div className='docCreatorMenu-layout-preview-window-wrapper'>
- <div className='docCreatorMenu-zoom-button-container'>
+ <div className='docCreatorMenu-layout-preview-window-wrapper' id={String(id) ?? undefined}>
+ {!zoomOption ? null : <div className='docCreatorMenu-zoom-button-container'>
<button
className='docCreatorMenu-zoom-button'
onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreviewScale *= 1.25))}>
@@ -283,15 +323,16 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreviewScale *= .75))}>
<FontAwesomeIcon icon={'plus'}/>
</button>
- </div>
+ </div>}
<div
- className='docCreatorMenu-layout-preview-window'
+ id={String(id) ?? undefined}
+ className={`docCreatorMenu-layout-preview-window ${small ? 'small' : ''}`}
style={{
- gridTemplateColumns: `repeat(${this.columnsCount}, ${scaledDown(docWidth)}px`,
+ gridTemplateColumns: `repeat(${altLayout ? altLayout.columns : this.columnsCount}, ${scaledDown(docWidth)}px`,
gridTemplateRows: `${scaledDown(docHeight)}px`,
gridAutoRows: `${scaledDown(docHeight)}px`,
- rowGap: `${scaledDown(this._layout.yMargin)}px`,
- columnGap: `${scaledDown(this._layout.xMargin)}px`
+ rowGap: `${scaledDown(layout.yMargin)}px`,
+ columnGap: `${scaledDown(layout.xMargin)}px`
}}>
{this._layout.type === LayoutType.Stacked ?
<div
@@ -365,32 +406,61 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
</div>
</div>
<button
- className='docCreatorMenu-menu-button'
+ className='docCreatorMenu-menu-button preview-toggle'
onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this._layoutPreview = !this._layoutPreview))}>
<FontAwesomeIcon icon={this._layoutPreview ? 'minus' : 'magnifying-glass'}/>
</button>
</div>
{this._layout.type ? this.layoutConfigOptions: null}
- {this._layoutPreview ? this.layoutPreviewContents : null}
+ {this._layoutPreview ? this.layoutPreviewContents(225) : null}
{selectionBox(60, 20, 'repeat', undefined, repeatOptions.map(num => <option onPointerDown={e => this._layout.repeat = num}>{`${num}x`}</option>))}
- <button
- className='docCreatorMenu-create-docs-button'
- style={{backgroundColor: this.canMakeDocs ? '' : 'rgb(155, 155, 155)', border: this.canMakeDocs ? '' : 'rgb(180, 180, 180)'}}
- onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction,
+ <hr className='docCreatorMenu-option-divider'/>
+ <div className='docCreatorMenu-general-options-container'>
+ <button
+ className='docCreatorMenu-save-layout-button'
+ onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction,
undoable(clickEv => {
clickEv.stopPropagation();
if (!this._selectedTemplate) return;
- const templateInfo: DataVizTemplateInfo = {doc: this._selectedTemplate, layout: this._layout, referencePos: {x: this._pageX + 450, y: this._pageY}, columns: this.columnsCount};
- this._dataViz?.createDocsFromTemplate(templateInfo);
- }, 'make docs')
+ const layout: DataVizTemplateLayout = {template: this._selectedTemplate, layout: {type: this._layout.type, xMargin: this._layout.xMargin, yMargin:this._layout.yMargin, repeat: 0}, columns: this.columnsCount, rows: this.rowsCount, docsNumList: this.docsToRender};
+ this._savedLayouts.push(layout);
+ }, 'make docs')
)
}>
- Create
- </button>
+ <FontAwesomeIcon icon='floppy-disk'/>
+ </button>
+ <button
+ className='docCreatorMenu-create-docs-button'
+ style={{backgroundColor: this.canMakeDocs ? '' : 'rgb(155, 155, 155)', border: this.canMakeDocs ? '' : 'solid 2px rgb(180, 180, 180)'}}
+ onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction,
+ undoable(clickEv => {
+ clickEv.stopPropagation();
+ if (!this._selectedTemplate) return;
+ const templateInfo: DataVizTemplateInfo = {doc: this._selectedTemplate, layout: this._layout, referencePos: {x: this._pageX + 450, y: this._pageY}, columns: this.columnsCount};
+ this._dataViz?.createDocsFromTemplate(templateInfo);
+ }, 'make docs')
+ )
+ }>
+ <FontAwesomeIcon icon='plus'/>
+ </button>
+ </div>
</div>
);
}
+ get renderSelectedViewType(){
+ switch (this._menuContent){
+ case 'templates':
+ return this.templatesPreviewContents;
+ case 'options':
+ return this.optionsMenuContents;
+ case 'saved':
+ return this.savedLayoutsPreviewContents;
+ default:
+ return undefined;
+ }
+ }
+
render() {
const topButton = (icon: string, opt: string, func: Function, tag: string) => {
return (
@@ -485,7 +555,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
<FontAwesomeIcon icon={'minus'}/>
</button>
</div>
- {this._menuContent === 'templates' ? this.templatesPreviewContents : this.optionsMenuContents}
+ {this.renderSelectedViewType}
</div>
</>
}
@@ -499,4 +569,12 @@ export interface DataVizTemplateInfo {
layout: {type: LayoutType, xMargin: number, yMargin: number, repeat: number};
columns: number;
referencePos: {x: number, y: number};
+}
+
+export interface DataVizTemplateLayout {
+ template: Doc;
+ docsNumList: number[];
+ layout: {type: LayoutType, xMargin: number, yMargin: number, repeat: number};
+ columns: number;
+ rows: number;
} \ No newline at end of file