import { action, computed, makeObservable, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { ObservableReactComponent } from "../../../../ObservableReactComponent"; import { DocCreatorMenu, LayoutType } from "../DocCreatorMenu"; import React from "react"; import { IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils"; import { emptyFunction } from "../../../../../../Utils"; import { undoable } from "../../../../../util/UndoManager"; import ReactLoading from "react-loading"; import { Doc, NumListCast, returnEmptyDoclist } from "../../../../../../fields/Doc"; import { StrCast } from "../../../../../../fields/Types"; import { DefaultStyleProvider } from "../../../../StyleProvider"; import { DocumentView } from "../../../DocumentView"; import { Transform } from "../../../../../util/Transform"; import { Docs, DocumentOptions } from "../../../../../documents/Documents"; interface TemplatesRenderPreviewWindowProps { menu: DocCreatorMenu; } @observer export class TemplatesRenderPreviewWindow extends ObservableReactComponent { @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 0, repeat: 0 }; @observable private renderedDocs: Doc[] = []; @observable private renderedDocCollection: Doc | undefined = undefined; @observable private loading: boolean = false; constructor(props: TemplatesRenderPreviewWindowProps) { super(props); makeObservable(this); this.updateRenderedPreviewCollection(); } @computed get canMakeDocs() { return this._props.menu._selectedTemplate !== undefined && this._layout !== undefined; } @computed get docsToRender() { if (this._props.menu.DEBUG_MODE) { return [1, 2, 3, 4]; } else { return NumListCast(this._props.menu._dataViz?.layoutDoc.dataViz_selectedRows); } } @computed get rowsCount() { switch (this._layout.type) { case LayoutType.FREEFORM: return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0; case LayoutType.CAROUSEL3D: return 1.8; default: return 1; } } @computed get columnsCount() { switch (this._layout.type) { case LayoutType.FREEFORM: return this._layout.columns ?? 0; case LayoutType.CAROUSEL3D: return 3; default: return 1; } } @action updateRenderedPreviewCollection = async () => { this.loading = true; this.renderedDocs = await this._props.menu.createDocsForPreview(); this.updateRenderedDocCollection(); }; /** * Updates the preview that shows how all docs will be rendered in the chosen collection type. @type the type of collection the docs should render to (ie. freeform, carousel, card) */ updateRenderedDocCollection = () => { if (!this.renderedDocs) return; const collectionFactory = (): ((docs: Doc[], options: DocumentOptions) => Doc) => { switch (this._layout.type) { case LayoutType.CAROUSEL3D: return Docs.Create.Carousel3DDocument; case LayoutType.FREEFORM: return Docs.Create.FreeformDocument; case LayoutType.CARD: return Docs.Create.CardDeckDocument; case LayoutType.MASONRY: return Docs.Create.MasonryDocument; case LayoutType.CAROUSEL: return Docs.Create.CarouselDocument; default: return Docs.Create.FreeformDocument; } // prettier-ignore }; const collection = collectionFactory()(this.renderedDocs, { isDefaultTemplateDoc: true, title: 'title', backgroundColor: 'gray', x: 200, y: 200, _width: 4000, _height: 4000, }); this.applyLayout(collection, this.renderedDocs); this.renderedDocCollection = collection; this.loading = false; this.forceUpdate(); }; @action updateMargin = (input: string, xOrY: 'x' | 'y') => { this._layout[`${xOrY}Margin`] = Number(input); setTimeout(() => { if (!this.renderedDocCollection || !this.renderedDocs) return; this.applyLayout(this.renderedDocCollection, this.renderedDocs); }); }; @action updateColumns = (input: string) => { this._layout.columns = Number(input); this.updateRenderedDocCollection(); }; applyLayout = (collection: Doc, docs: Doc[]) => { const { horizontalSpan, verticalSpan } = this.previewInfo; collection._height = verticalSpan; collection._width = horizontalSpan; const columns: number = this._layout.columns ?? this.columnsCount; const xGap: number = this._layout.xMargin; const yGap: number = this._layout.yMargin; const startX: number = -Number(collection._width) / 2; const startY: number = -Number(collection._height) / 2; const docHeight: number = Number(docs[0]._height); const docWidth: number = Number(docs[0]._width); if (columns === 0 || docs.length === 0) { return; } let i: number = 0; let docsChanged: number = 0; let curX: number = startX; let curY: number = startY; while (docsChanged < docs.length) { while (i < columns && docsChanged < docs.length) { docs[docsChanged].x = curX; docs[docsChanged].y = curY; curX += docWidth + xGap; ++docsChanged; ++i; } i = 0; curX = startX; curY += docHeight + yGap; } }; @computed get previewInfo() { const docHeight: number = Number(this.renderedDocs[0]._height); const docWidth: number = Number(this.renderedDocs[0]._width); const layout = this._layout; return { docHeight: docHeight, docWidth: docWidth, horizontalSpan: (docWidth + layout.xMargin) * this.columnsCount - layout.xMargin, verticalSpan: (docHeight + layout.yMargin) * this.rowsCount - layout.yMargin, }; } get layoutConfigOptions() { const optionInput = (icon: string, func: (input: string) => void, def?: number, key?: string, noMargin?: boolean) => { return (
func(e.currentTarget.value)} className="docCreatorMenu-input config layout-config" />
); }; switch (this._layout.type) { case LayoutType.FREEFORM: return (
{optionInput('arrows-up-down', (input: string) => this.updateMargin(input, 'y'), this._layout.xMargin, '2')} {optionInput('arrows-left-right', (input: string) => this.updateMargin(input, 'x'), this._layout.xMargin, '3')} {optionInput('table-columns', this.updateColumns, this._layout.columns, '4', true)}
); default: break; } } layoutPreviewContents = action(() => { return this.loading ? (
) : !this.renderedDocCollection ? null : (
this._props.menu._menuDimensions.width - 80} PanelHeight={() => this._props.menu._menuDimensions.height - 105} ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)} renderDepth={5} whenChildContentsActiveChanged={emptyFunction} focus={emptyFunction} styleProvider={DefaultStyleProvider} addDocTab={this._props.menu._props.addDocTab} pinToPres={() => undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} fitContentsToBox={returnFalse} fitWidth={returnFalse} hideDecorations={true} />
); }); selectionBox = (width: number, height: number, icon: string, specClass?: string, options?: JSX.Element[], manual?: boolean): JSX.Element => { return (
{manual ? ( ) : ( )}
); }; layoutOption = (option: LayoutType, optStyle?: object, specialFunc?: () => void) => { return (
this._props.menu.setUpButtonClick(e, () => { specialFunc?.(); runInAction(() => { this._layout.type = option; this.updateRenderedDocCollection(); }); }) }> {option}
); }; get optionsMenuContents() { const repeatOptions = [0, 1, 2, 3, 4, 5]; return (
{this._layout.type ? this._layout.type.toUpperCase() : 'Choose Layout'}
{this.layoutOption(LayoutType.FREEFORM, undefined, () => { if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length)); })} {this.layoutOption(LayoutType.CAROUSEL)} {this.layoutOption(LayoutType.CAROUSEL3D)} {this.layoutOption(LayoutType.MASONRY)}
{this._layout.type ? this.layoutConfigOptions : null} {this.layoutPreviewContents()} {this.selectionBox( 60, 20, 'repeat', undefined, repeatOptions.map(num => ) )}
); } render() { return this.optionsMenuContents } }