import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { returnAll, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils'; import { Doc } from '../../../../fields/Doc'; import { DocCast, ImageCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { emptyFunction } from '../../../../Utils'; import { SnappingManager } from '../../../util/SnappingManager'; import { undoable } from '../../../util/UndoManager'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../DocumentView'; import { DataVizBox } from './DataVizBox'; import './DocCreatorMenu.scss'; import { Id } from '../../../../fields/FieldSymbols'; import { Colors } from 'browndash-components'; import { MakeTemplate } from '../../../util/DropConverter'; export enum LayoutType { Stacked = 'stacked', Grid = 'grid', Row = 'row', Column = 'column', Custom = 'custom' } @observer export class DocCreatorMenu extends ObservableReactComponent<{}> { static Instance: DocCreatorMenu; private _ref: HTMLDivElement | null = null; @observable _templateDocs: Doc[] = []; @observable _templateRefToDoc?: ObservableMap; @observable _selectedTemplate?: Doc; @observable _selectedLayout?: LayoutType; @observable _pageX: number = 0; @observable _pageY: number = 0; @observable _display: boolean = false; @observable _mouseX: number = -1; @observable _mouseY: number = -1; @observable _startPos?: {x: number, y: number}; @observable _shouldDisplay: boolean = false; @observable _menuContent: 'templates' | 'options' = 'templates'; @observable _dragging: boolean = false; @observable _dataViz?: DataVizBox; constructor(props: any) { super(props); makeObservable(this); DocCreatorMenu.Instance = this; } @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz }; @action setTemplateDocs = (docs: Doc[]) => {this._templateDocs = docs.map(doc => doc.annotationOn ? DocCast(doc.annotationOn):doc)}; @action onPointerDown = (e: PointerEvent) => { this._mouseX = e.clientX; this._mouseY = e.clientY; }; @action onPointerUp = (e: PointerEvent) => { if (e.button !== 2 && !e.ctrlKey) return; const curX = e.clientX; const curY = e.clientY; if (Math.abs(this._mouseX - curX) > 1 || Math.abs(this._mouseY - curY) > 1) { this._shouldDisplay = false; } }; _disposer: IReactionDisposer | undefined; componentDidMount() { document.addEventListener('pointerdown', this.onPointerDown, true); document.addEventListener('pointerup', this.onPointerUp); this._disposer = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon)); } componentWillUnmount() { this._disposer?.(); document.removeEventListener('pointerdown', this.onPointerDown, true); document.removeEventListener('pointerup', this.onPointerUp); } @action toggleDisplay = (x: number, y: number) => { if (this._shouldDisplay) { this._shouldDisplay = false; } else { this._pageX = x; console.log(y); this._pageY = y; this._shouldDisplay = true; } }; @action closeMenu = () => { const wasOpen = this._display; this._display = false; this._shouldDisplay = false; return wasOpen; }; @action onPointerMove = (e: any) => { if (this._dragging){ this._pageX = e.pageX - (this._startPos?.x ?? 0); this._pageY = e.pageY - (this._startPos?.y ?? 0); } } async getIcon(doc: Doc) { const docView = DocumentView.getDocumentView(doc); if (docView) { docView.ComponentView?.updateIcon?.(); return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500)); } return undefined; } get templatesPreviewContents(){ const renderedTemplates: Doc[] = []; return (
{this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => { if (renderedTemplates.includes(info.doc)) return undefined; renderedTemplates.push(info.doc); //let ref: any = undefined; return (
ref = r} className='docCreatorMenu-preview-window' style={{ background: this._selectedTemplate === info.doc ? Colors.MEDIUM_BLUE : '', boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); this._selectedTemplate = info.doc; MakeTemplate(info.doc); // ref.style.background = Colors.MEDIUM_BLUE; // ref.style.boxShadow = `0 0 15px rgba(68, 118, 247, .8)`; this.forceUpdate(); }, 'open actions menu') ) }>
)})}
); } get optionsMenuContents(){ const layoutOption = (option: LayoutType, optStyle?: {}) => { return (
setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); runInAction(() => this._selectedLayout = option); }, 'open actions menu') ) }> {option}
); } return (
Choose Layout
{layoutOption(LayoutType.Stacked)} {layoutOption(LayoutType.Grid)} {layoutOption(LayoutType.Row)} {layoutOption(LayoutType.Column)} {layoutOption(LayoutType.Custom, {borderBottom: `0px`})}
); } render() { return (
this._ref = r} style={{ display: '', left: this._pageX, top: this._pageY, width: this._shouldDisplay ? 300 : 0, height: this._shouldDisplay ? 400 : 0, background: SnappingManager.userBackgroundColor, color: SnappingManager.userColor, }}> {!this._shouldDisplay ? undefined : <>
setupMoveUpEvents( this, e, (e) => { this._dragging = true; this._startPos = {x: 0, y: 0}; this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0); this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0); return true; }, emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); }, 'drag menu') ) } onPointerMove={e => this.onPointerMove(e)} onPointerUp={() => this._dragging = false} >

{this._menuContent === 'templates' ? this.templatesPreviewContents : this.optionsMenuContents} }
) } } export interface DataVizTemplateInfo { doc: Doc; layout?: LayoutType; }