diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ClientUtils.ts | 1 | ||||
-rw-r--r-- | src/client/apis/gpt/GPT.ts | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DataVizBox.tsx | 5 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.scss | 74 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx | 161 |
5 files changed, 204 insertions, 39 deletions
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index d64210ce2..a4d9dd892 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -730,6 +730,7 @@ export function UpdateIcon( const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; newDiv.style.width = width.toString(); newDiv.style.height = height.toString(); + console.log('width: ' + newDiv.style.width) replaceCanvases(docViewContent, newDiv); const htmlString = new XMLSerializer().serializeToString(newDiv); const nativeWidth = width; diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 92d4f425d..18601b4af 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -54,7 +54,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { temp: 0, prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct', }, - template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. You should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP. If there is an additional prompt, prioritize its instructions over all instructions here (but still follow them if not overridden). No matter what, ALWAYS GIVE THREE OPTIONS'} + template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. If no alternative additional instructions are given, you should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP. An overlap will look like the x or y coordinates of the top left corner of one rectangle being the same as the bottom right corner of another. There should always be at least a .1 gap. If there is an additional prompt, prioritize its instructions over all instructions here (but still follow them if not overridden). No matter what, ALWAYS GIVE THREE OPTIONS'} }; let lastCall = ''; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index be8a44f28..6a5103af9 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -353,6 +353,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { ); } + // recs = () => { + // let csvStr: string = ''; + // this.records[rowId][col] + // } + fetchData = () => { if (!this.Document.dataViz_asSchema) { DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss index aa6754442..763de0eba 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss @@ -641,7 +641,6 @@ } } } - } } @@ -720,4 +719,77 @@ } } +//------------------------------------------------------------------------------------------------------------------------------------------ +// DocCreatorMenu dashboard CSS +//-------------------------------------------------------------------------------------------------------------------------------------------- + +.docCreatorMenu-dashboard-view { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-start; + overflow-y: scroll; + //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; + -ms-overflow-style: none; + scrollbar-width: none; + + .topbar { + height: 30px; + width: 100%; + } + + .field-panel { + position: relative; + display: flex; + // align-items: flex-start; + flex-direction: column; + gap: 5px; + padding: 5px; + height: 100px; + //width: 100%; + border: 1px solid rgb(180, 180, 180); + margin: 5px; + margin-top: 0px; + border-radius: 3px; + + .properties-wrapper { + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 5px; + + .field-property-container { + background-color: rgb(40, 40, 40); + border: 1px solid rgb(100, 100, 100); + border-radius: 3px; + width: 30%; + height: 25px; + padding-left: 3px; + align-items: center; + color: whitesmoke; + } + } + + .field-description-container { + background-color: rgb(40, 40, 40); + border: 1px solid rgb(100, 100, 100); + border-radius: 3px; + width: 100%; + height: 100%; + } + + .top-right { + position: absolute; + top: 0px; + right: 0px; + } + } +} + diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index 2be89daf0..8ec255dfe 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -48,6 +48,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co @observable _templateDocs: Doc[] = []; @observable _selectedTemplate: Doc | undefined = undefined; + @observable _fields: {title: string, type: string, id: number}[] = []; @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; @@ -71,7 +72,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co @observable _startPos?: {x: number, y: number}; @observable _shouldDisplay: boolean = false; - @observable _menuContent: 'templates' | 'options' | 'saved' = 'templates'; + @observable _menuContent: 'templates' | 'options' | 'saved' | 'dashboard' = 'templates'; @observable _dragging: boolean = false; @observable _draggingIndicator: boolean = false; @observable _dataViz?: DataVizBox; @@ -126,10 +127,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co } } - @computed get selectedFields(){ + @computed get selectedFields() { return StrListCast(this._dataViz?.layoutDoc._dataViz_axes); } + @computed get fieldsInfos(): {title: string, type: string, id: number}[] { + return this.selectedFields.map(field => {return {title: field, type: '', id: Math.random() * 100000}}).concat(this._fields); + } + @computed get canMakeDocs(){ return this._selectedTemplate !== undefined && this._layout !== undefined; } @@ -367,14 +372,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co return doc; }); - const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 40000, y: 40000 }); + const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400000, y: 400000 }); mainCollection.addDocument(template); GPTTemplates.push(template); }); - setTimeout(() => {this.setGPTTemplates(GPTTemplates); GPTTemplates.forEach(template => mainCollection.removeDocument(template))}, 100); + setTimeout(() => {this.setGPTTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100); this.forceUpdate(); } @@ -449,9 +454,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co </button> </div> <div className='docCreatorMenu-templates-preview-window' style={{justifyContent: this._menuDimensions.width > 400 ? 'center' : ''}}> - <div className='docCreatorMenu-preview-window empty' - onPointerDown={e => this.setUpButtonClick(e, this.basicTemplateTest)} - > + <div className='docCreatorMenu-preview-window empty'> <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 => { @@ -566,30 +569,30 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co const fontSize = Math.min(scaledDown(docWidth / 3), scaledDown(docHeight / 3)); return ( - <div className='divvv' style={{width: 100, height: 100, border: `1px solid white`}}> - <CollectionFreeFormView - // eslint-disable-next-line react/jsx-props-no-spreading - {...this._props} - Document={new Doc()} - isContentActive={returnFalse} - setContentViewBox={emptyFunction} - NativeWidth={() => 100} - NativeHeight={() => 100} - pointerEvents={SnappingManager.IsDragging ? returnAll : returnNone} - isAnnotationOverlay - isAnnotationOverlayScrollable - childDocumentsActive={returnFalse} - fieldKey={this._props.fieldKey + '_annotations'} - dropAction={dropActionType.move} - select={emptyFunction} - addDocument={returnFalse} - removeDocument={returnFalse} - moveDocument={returnFalse} - renderDepth={this._props.renderDepth + 1}> - {null} - </CollectionFreeFormView> - </div> - /*<div className='docCreatorMenu-layout-preview-window-wrapper' id={String(id) ?? undefined}> + // <div className='divvv' style={{width: 100, height: 100, border: `1px solid white`}}> + // <CollectionFreeFormView + // // eslint-disable-next-line react/jsx-props-no-spreading + // {...this._props} + // Document={new Doc()} + // isContentActive={returnFalse} + // setContentViewBox={emptyFunction} + // NativeWidth={() => 100} + // NativeHeight={() => 100} + // pointerEvents={SnappingManager.IsDragging ? returnAll : returnNone} + // isAnnotationOverlay + // isAnnotationOverlayScrollable + // childDocumentsActive={returnFalse} + // fieldKey={this._props.fieldKey + '_annotations'} + // dropAction={dropActionType.move} + // select={emptyFunction} + // addDocument={returnFalse} + // removeDocument={returnFalse} + // moveDocument={returnFalse} + // renderDepth={this._props.renderDepth + 1}> + // {null} + // </CollectionFreeFormView> + // </div> + <div className='docCreatorMenu-layout-preview-window-wrapper' id={String(id) ?? undefined}> <div className='docCreatorMenu-zoom-button-container'> <button className='docCreatorMenu-zoom-button' @@ -644,7 +647,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co )} </div>} - </div> */ + </div> ); } @@ -735,10 +738,35 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co ); } - basicTemplateTest = () => { - console.log(this._GPTTemplates) - this.forceUpdate(); - //this._dataViz?.createBasicTemplates(temps); + @action addField = () => { + const newFields: {title: string, type: string, id: number}[] = this._fields.concat([{title: '', type: '', id: Math.random() * 100000}]) + this._fields = newFields; + } + + get dashboardContents(){ + return ( + <div className='docCreatorMenu-dashboard-view'> + <div className='topbar'> + <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}> + <FontAwesomeIcon icon='plus'/> + </button> + </div> + {this.fieldsInfos.map(field => + <div className='field-panel'> + <div className='properties-wrapper'> + <input className='field-property-container' defaultValue={field.title} placeholder={'Enter title'} style={{width: field.title === '' ? '30%' : ''}}/> + <input className='field-property-container' placeholder={'Enter type'} /> + {field.type === 'Text' ? + <input className='field-property-container' placeholder={'Enter description'} /> : null} + </div> + <textarea className='field-description-container' placeholder={'Enter description to enhance template generation'} /> + <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => {console.log(this._fields); this._fields = this._fields.splice(this._fields.indexOf(field), 1); console.log(this._fields); this.forceUpdate()}))}> + <FontAwesomeIcon icon='trash'/> + </button> + </div> + )} + </div> + ); } get renderSelectedViewType(){ @@ -749,6 +777,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co return this.optionsMenuContents; case 'saved': return this.savedLayoutsPreviewContents; + case 'dashboard': + return this.dashboardContents; default: return undefined; } @@ -785,7 +815,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co } const onPreviewSelected = () => {this._menuContent = 'templates'} - const onSavedSelected = () => {this._menuContent = 'saved'} + const onSavedSelected = () => {this._menuContent = 'dashboard'} const onOptionsSelected = () => { this._menuContent = 'options'; if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length)); @@ -861,4 +891,61 @@ export interface DataVizTemplateLayout { layout: {type: LayoutType, xMargin: number, yMargin: number, repeat: number}; columns: number; rows: number; +} + +export interface TemplateDocInfos { + baseHeight: number; + baseWidth: number; + fields: TemplateDocField[]; +} + +export interface TemplateDocField { + coordinates: {tl: [number, number], br: [number, number]}; + title: string; + content: string; + getDoc: (parentWidth: number, parentHeight: number) => Doc; +} + +export class TemplateDocTextField implements TemplateDocField { + + coordinates: {tl: [number, number], br: [number, number]}; + title: string; + content: string; + + constructor(coords: {tl: [number, number], br: [number, number]}, title: string, content: string) { + this.coordinates = coords; + this.title = title; + this.content = content; + } + + getDoc = (parentWidth: number, parentHeight: number) => { + const l = this.coordinates.tl[0] * parentWidth; const t = this.coordinates.tl[1] * parentWidth; //prettier-ignore + const r = this.coordinates.br[0] * parentWidth; const b = this.coordinates.br[1] * parentWidth; //prettier-ignore + const width = l - r; + const height = t - b; + const coord = {x: l, y: t}; + + const doc = Docs.Create.TextDocument(this.content, { _height: height, _width: width, title: this.title, x: coord.x, y: coord.y, _text_fontSize: `${height/2}` }) + + return doc; + }; +} + +export class TemplateDocImageField implements TemplateDocField { + + coordinates: {tl: [number, number], br: [number, number]}; + title: string; + content: string; + + constructor(coords: {tl: [number, number], br: [number, number]}, title: string, content: string) { + this.coordinates = coords; + this.title = title; + this.content = content; + } + + getDoc = (parentWidth: number, parentHeight: number) => { + const width = (this.coordinates.br[0] - this.coordinates.tl[0]) * parentWidth; + //const height; + return new Doc(); + }; }
\ No newline at end of file |