aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-08-08 10:38:35 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-08-08 10:38:35 -0400
commit4949c68f38049da55ceaa3e95ea155f38d6a3748 (patch)
treee32645b6c0df8a6ef3aec0595d4f2c44e5d367ed /src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
parent9119b9f08f62bb5228206487b047d6e1e75d5e9e (diff)
UI for GPT templates in doccreator menu
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx')
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx147
1 files changed, 111 insertions, 36 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 411257ff7..781cbcb55 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -3,7 +3,7 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnAll, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
-import { Doc, NumListCast } from '../../../../fields/Doc';
+import { Doc, NumListCast, StrListCast } from '../../../../fields/Doc';
import { DocCast, ImageCast } from '../../../../fields/Types';
import { ImageField } from '../../../../fields/URLField';
import { emptyFunction } from '../../../../Utils';
@@ -17,6 +17,9 @@ import { Id } from '../../../../fields/FieldSymbols';
import { Colors, IconButton, Size } from 'browndash-components';
import { MakeTemplate } from '../../../util/DropConverter';
import { DragManager } from '../../../util/DragManager';
+import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
+import { Docs } from '../../../documents/Documents';
export enum LayoutType {
Stacked = 'stacked',
@@ -41,6 +44,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
@observable _layoutPreviewScale: number = 1;
@observable _savedLayouts: DataVizTemplateLayout[] = [];
+ @observable _GPTTemplates: Doc[] | undefined = undefined;
+ @observable _GPTOpt: boolean = false;
+ @observable _userPrompt: string = '';
+
@observable _pageX: number = 0;
@observable _pageY: number = 0;
@observable _indicatorX: number | undefined = undefined;
@@ -105,6 +112,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
}
}
+ @computed get selectedFields(){
+ return StrListCast(this._dataViz?.layoutDoc._dataViz_axes);
+ }
+
@computed get canMakeDocs(){
return this._selectedTemplate !== undefined && this._layout !== undefined;
}
@@ -254,8 +265,8 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY;
const {height, width, x, y} = this._initDimensions;
- this._menuDimensions.width = Math.max(100, scale.x * width);
- this._menuDimensions.height = Math.max(100, scale.y * height);
+ this._menuDimensions.width = Math.max(300, scale.x * width);
+ this._menuDimensions.height = Math.max(200, scale.y * height);
this._pageX = x + translation.x;
this._pageY = y + translation.y;
};
@@ -293,10 +304,104 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
&& this._layout.columns === layout.columns;
}
+ generateTemplates = async (inputText: string) => {
+ let prompt: string = 'Please generate for the fields:';
+ this.selectedFields?.forEach(field => prompt += ` ${field},`)
+ prompt += ` Additional prompt: ${inputText}`;
+
+ try {
+ const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
+
+ if (res) {
+ const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
+ this.createGeneratedTemplates(templates, 500, 500);
+ }
+ } catch (err) {
+ console.error(err);
+ }
+
+ }
+
+ createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => {
+ const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+
+ layouts.forEach(layout => {
+ const fields: Doc[] = layout.fieldVals.map(field => {
+ const left: number = Number(field.tlx) * tempWidth / 2; const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore
+ const right: number = Number(field.brx) * tempWidth / 2; const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore
+ const height = bottom - top;
+ const width = right - left;
+ const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/$$/g, ''), x: left, y: top });
+ return doc;
+ });
+
+ const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400, y: 400 });
+ mainCollection.addDocument(template);
+ });
+ }
+
get templatesPreviewContents(){
const renderedTemplates: Doc[] = [];
+
+ const GPTOptions =
+ <div></div>
+
+
return (
- <div className='docCreatorMenu-preview-container'
+ <div className='docCreatorMenu-templates-view'>
+ <div className='docCreatorMenu-section'>
+ <div className='docCreatorMenu-section-topbar'>
+ <div className='docCreatorMenu-section-title'>Suggested Templates</div>
+ <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
+ <FontAwesomeIcon icon='gear'/>
+ </button>
+ </div>
+ <div className='docCreatorMenu-GPT-templates-preview'>
+ <div className='docCreatorMenu-preview-window empty GPT'></div>
+ <div className='docCreatorMenu-preview-window empty GPT'></div>
+ <div className='docCreatorMenu-preview-window empty GPT'></div>
+ <div className='docCreatorMenu-preview-window empty GPT'></div>
+ </div>
+ {this._GPTOpt ? (<div className='docCreatorMenu-GPT-options'>
+ <div className='docCreatorMenu-GPT-options-container'>
+ <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}>
+ <FontAwesomeIcon icon='plus'/>
+ </button>
+ <input className='docCreatorMenu-GPT-prompt-input'/>
+ </div>
+ {this._GPTOpt ? GPTOptions : null}
+ </div>) : null}
+ </div>
+ <hr className='docCreatorMenu-option-divider'/>
+ <div className='docCreatorMenu-section'>
+ <div className='docCreatorMenu-section-topbar'>
+ <div className='docCreatorMenu-section-title'>Your Templates</div>
+ <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
+ <FontAwesomeIcon icon='gear'/>
+ </button>
+ </div>
+ <div className='docCreatorMenu-GPT-templates-preview'>
+ <div className='docCreatorMenu-preview-window empty'
+ onPointerDown={e => this.setUpButtonClick(e, this.basicTemplateTest)}
+ >
+ <FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
+ </div>
+ {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);
+ return (<div
+ className='docCreatorMenu-preview-window'
+ style={{
+ 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>
+ </div>
+ {/* <div className='docCreatorMenu-preview-container'
style={{gridTemplateColumns: `repeat(${Math.floor((this._menuDimensions.width - 10) / 140)}, 140px)`}}>
{this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => {
if (renderedTemplates.includes(info.doc)) return undefined;
@@ -316,6 +421,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
>
<FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
</div>
+ </div> */}
</div>
);
}
@@ -546,12 +652,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
}
basicTemplateTest = () => {
- const temps: {width: number; height: number; x: number; y: number; title: string}[] = [
- {width: 200, height: 50, x: -100, y: -200, title: 'title'},
- {width: 300, height: 300, x: -150, y: -100, title: 'image'},
- {width: 200, height: 50, x: -100, y: -200, title: 'description'},
- ]
- this._dataViz?.generateTemplates();
+ this.generateTemplates(this._userPrompt);
//this._dataViz?.createBasicTemplates(temps);
}
@@ -609,31 +710,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
return (
<div className='docCreatorMenu'>
{!this._shouldDisplay ? undefined :
- <>
- {/* <div className='docCreatorMenu-placement-indicator'
- style={{
- display: '',
- left: this._indicatorX ?? this._pageX + 300,
- top: this._indicatorY ?? this._pageY,
- }}
- onPointerMove={e => this.onPointerMove(e)}
- onPointerDown={e =>
- setupMoveUpEvents(
- this,
- e,
- (e) => {
- this._draggingIndicator = 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')
- )
- }/> */}
<div
className="docCreatorMenu-cont"
ref={r => this._ref = r}
@@ -681,7 +757,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
</div>
{this.renderSelectedViewType}
</div>
- </>
}
</div>
)