aboutsummaryrefslogtreecommitdiff
path: root/src
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
parent9119b9f08f62bb5228206487b047d6e1e75d5e9e (diff)
UI for GPT templates in doccreator menu
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx45
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.scss128
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx147
-rw-r--r--src/client/views/nodes/ImageBox.tsx1
4 files changed, 228 insertions, 93 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index c5a1da1da..a6d3bfa49 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -568,51 +568,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.applyLayout(templateInfo, docs);
}
- generateTemplates = async () => {
- try {
- const res = await gptAPICall('Please generate for the fields: Image, Description, Divider, Response', 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);
- //console.log(res);
- }
- } 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.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; //prettier-ignore
- 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: 250, 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);
- });
- }
-
- createBasicTemplates = (colsToLayout: {width: number, height: number, x: number, y: number, title: string}[]) => {
- const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-
- const fields: Doc[] = colsToLayout.map(layout => {
- const field = Docs.Create.TextDocument('', { _height: layout.height, _width: layout.width, title: layout.title, x: layout.x, y: layout.y });
- return field;
- });
-
- const template = Docs.Create.FreeformDocument(fields, { _height: 500, _width: 500, title: 'template', x: 400, y: 400 })
-
- mainCollection.addDocument(template);
- }
-
/**
* creates a new dataviz document filter from this one
* it appears to the right of this document, with the
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
index b3bacb13c..e2b4014bd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
@@ -22,14 +22,14 @@
}
.docCreatorMenu-menu-button {
- width: 30px;
- height: 30px;
+ width: 25px;
+ height: 25px;
background: whitesmoke;
- background-color: rgb(34, 34, 37);
+ background-color: rgb(50, 50, 50);
border-radius: 5px;
border: 1px solid rgb(180, 180, 180);
padding: 0px;
- font-size: 14px;
+ font-size: 13px;
//box-shadow: 3px 3px rgb(29, 29, 31);
&:hover {
@@ -222,7 +222,7 @@
.docCreatorMenu-option-divider {
border-top: 1px solid rgb(180, 180, 180);
- width: 80%;
+ width: 95%;
margin-top: 10px;
margin-bottom: 10px;
}
@@ -256,6 +256,18 @@
// DocCreatorMenu templates preview CSS
//--------------------------------------------------------------------------------------------------------------------------------------------
+.docCreatorMenu-templates-view {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+ margin: 5px;
+ margin-top: 0px;
+ width: calc(100% - 10px);
+ height: calc(100% - 30px);
+ border: 1px solid rgb(180, 180, 180);
+ border-radius: 5px;
+}
.docCreatorMenu-preview-container {
display: grid;
@@ -263,20 +275,18 @@
grid-template-rows: 140px;
grid-auto-rows: 141px;
overflow-y: scroll;
- margin: 5px;
+ margin: 0px;
margin-top: 0px;
- width: calc(100% - 10px);
- height: calc(100% - 30px);
- border: 1px solid rgb(180, 180, 180);
- border-radius: 5px;
+ width: 100%;
+ height: 100%;
}
.docCreatorMenu-preview-window {
display: flex;
justify-content: center;
align-items: center;
- width: 125px;
- height: 125px;
+ width: 113px;
+ height: 113px;
margin-top: 10px;
margin-left: 10px;
border: 1px solid rgb(163, 163, 163);
@@ -295,9 +305,103 @@
&.empty {
font-size: 35px;
+ flex: 0 0 auto;
+
+ &.GPT {
+ margin-top: 0px;
+ }
+ }
+}
+
+.docCreatorMenu-section {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ margin: 0px;
+ width: 100%;
+ height: 250;
+ flex: 0 0 auto;
+}
+
+.docCreatorMenu-GPT-options-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ width: auto;
+ margin: 0px;
+ margin-top: 5px;
+ padding: 0px;
+}
+
+.docCreatorMenu-GPT-templates-preview {
+ display: flex;
+ flex-direction: row;
+ //justify-content: center;
+ align-items: center;
+ overflow-y: scroll;
+ position: relative;
+ height: 125px;
+ width: calc(100% - 10px);
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+}
+
+.docCreatorMenu-section-topbar {
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+
+ .section-reveal-options {
+ margin: 0px;
+ margin-left: auto;
+ border: 0px;
+ background: none;
+ }
+}
+
+.docCreatorMenu-section-title {
+ border: 1px solid rgb(163, 163, 163);
+ border-top: 0px;
+ border-left: 0px;
+ border-bottom-right-radius: 5px;
+ font-size: 12px;
+ padding: 2px;
+ padding-left: 3px;
+ padding-right: 3px;
+ margin-bottom: 3px;
+}
+
+.docCreatorMenu-GPT-generate {
+ height: 30px;
+ width: 30px;
+ background-color: rgb(176, 229, 149);
+ border: 1px solid rgb(126, 219, 80);
+ border-radius: 5px;
+ padding: 0px;
+ font-size: 14px;
+ color: white;
+ letter-spacing: 1px;
+ flex: 0 0 auto;
+
+ &:hover {
+ background-color: rgb(129, 223, 83);
+ border: 2px solid rgb(80, 185, 28);
}
}
+.docCreatorMenu-GPT-prompt-input {
+ width: 140px;
+ overflow-y: scroll;
+ border: 1px solid rgb(180, 180, 180);
+ background-color: rgb(35, 35, 35);
+ border-radius: 3px;
+}
+
//------------------------------------------------------------------------------------------------------------------------------------------
// DocCreatorMenu options CSS
//--------------------------------------------------------------------------------------------------------------------------------------------
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>
)
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 92a5a1533..faea05104 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -295,6 +295,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get nativeSize() {
TraceMobx();
+ if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0}
const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500));
const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500));
const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1);