aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2025-05-11 21:18:55 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2025-05-11 21:18:55 -0400
commit4219c751c0f984fac6e5995c1ab955a8d63a28cd (patch)
treee638ff6aeb977f175916bcf14a8e332ae6f47dac /src
parente62f51bacace3d91f388202135426445721097cc (diff)
many changes to firefly UI (options added) and starting work on finalizing conditionals
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts14
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss300
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx36
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx160
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx32
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx10
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts23
-rw-r--r--src/client/views/smartdraw/DrawingFillHandler.tsx5
-rw-r--r--src/server/ApiManagers/FireflyManager.ts6
9 files changed, 296 insertions, 290 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
index d11f05766..030c6db95 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
@@ -20,7 +20,7 @@ export class TemplateManager {
templates: Template[] = [];
- fieldConditions: Record<string, Conditional[]> = {};
+ conditionalFieldLogic: Record<string, Conditional[]> = {};
constructor(templateSettings: FieldSettings[]) {
makeAutoObservable(this);
@@ -40,16 +40,16 @@ export class TemplateManager {
};
addFieldCondition = (fieldTitle: string, condition: Conditional) => {
- if (this.fieldConditions[fieldTitle] === undefined) {
- this.fieldConditions[fieldTitle] = [condition];
+ if (this.conditionalFieldLogic[fieldTitle] === undefined) {
+ this.conditionalFieldLogic[fieldTitle] = [condition];
} else {
- this.fieldConditions[fieldTitle].push(condition);
+ this.conditionalFieldLogic[fieldTitle].push(condition);
}
}
removeFieldCondition = (fieldTitle: string, condition: Conditional) => {
- if (this.fieldConditions[fieldTitle]) {
- this.fieldConditions[fieldTitle] = this.fieldConditions[fieldTitle].filter(cond => cond !== condition);
+ if (this.conditionalFieldLogic[fieldTitle]) {
+ this.conditionalFieldLogic[fieldTitle] = this.conditionalFieldLogic[fieldTitle].filter(cond => cond !== condition);
}
}
@@ -84,6 +84,8 @@ export class TemplateManager {
await applyGPTContent();
+ templateCopy.applyConditionalLogic(this.conditionalFieldLogic);
+
return templateCopy.getRenderedDoc();
};
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index 2a1a79029..8ac718fb7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -33,6 +33,7 @@
&:hover {
box-shadow: none;
+ background-color: rgb(60, 60, 65);
}
&.no-margin {
@@ -57,42 +58,6 @@
margin-left: 0px;
font-size: 12px;
}
-
- &.close-menu {
- font-size: 12px;
- width: 18px;
- height: 18px;
- font-size: 12px;
- margin-left: auto;
- margin-right: 5px;
- margin-bottom: 3px;
- }
-
- &.options {
- margin-left: 0px;
- }
-
- &:hover {
- background-color: rgb(60, 60, 65);
- }
-
- &.top-bar {
- border-bottom: 25px solid #555;
- border-left: 12px solid transparent;
- border-right: 12px solid transparent;
- // border-top-left-radius: 5px;
- // border-top-right-radius: 5px;
- border-radius: 0px;
- height: 0;
- width: 50px;
- }
-
- &.preview-toggle {
- margin: 0px;
- border-top-left-radius: 0px;
- border-bottom-left-radius: 0px;
- border-left: 0px;
- }
}
.docCreatorMenu-top-buttons-container {
@@ -400,30 +365,6 @@
}
-.docCreatorMenu-variation-prompt-input {
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- align-items: center;
- margin: 5px;
- gap: 15px;
- height: 30px;
- width: 100%;
-}
-
-.docCreatorMenu-variation-prompt-input-textbox {
- height: 100%;
- width: 80%;
- color: white;
- margin-top: 1%;
- margin-bottom: 1%;
- margin-left: 5%;
- background-color: rgb(50, 50, 50);
- border-radius: 5px;
- overflow: hidden;
- resize: none;
-}
-
.docCreatorMenu-variations-tab {
flex-grow: .5;
}
@@ -435,6 +376,7 @@
position: relative;
flex-grow: 1;
height: 100%;
+ width: 100%;
margin: 0px;
margin-top: 0px;
margin-bottom: 0px;
@@ -446,7 +388,7 @@
justify-content: center;
align-items: center;
position: absolute;
- width: 100%;
+ width: calc(100% - 10px);
bottom: 0px;
margin: 0px;
margin-bottom: 10px;
@@ -457,11 +399,18 @@
.docCreatorMenu-templates-preview-window {
display: grid;
justify-content: space-evenly;
+ row-gap: 2rem;
grid-template-columns: repeat(auto-fill, minmax(225px, 30%));
- gap: 1rem;
margin: 5px;
width: calc(100% - 10px);
+ height: 100%;
padding-bottom: 40px;
+
+ &.scrolling {
+ overflow-y: scroll;
+ max-height: 300px;
+ padding-bottom: 0px;
+ }
}
.divvv{
@@ -847,108 +796,6 @@
background-color: rgb(50, 50, 50);
}
-// .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;
-// flex: 0 0 auto;
-
-// .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-type-selection-container {
-// display: flex;
-// flex-direction: row;
-// align-items: center;
-// background-color: rgb(40, 40, 40);
-// border: 1px solid rgb(100, 100, 100);
-// border-radius: 3px;
-// width: 31%;
-// height: 25px;
-// padding-left: 3px;
-// color: whitesmoke;
-
-// .placeholder {
-// color: gray;
-// }
-
-// &:hover .placeholder {
-// display: none;
-// }
-
-// .bubbles {
-// display: none;
-// }
-
-// .text {
-// margin-top: 5px;
-// margin-bottom: 5px;
-// }
-
-// &:hover .bubbles {
-// display: flex;
-// flex-direction: row;
-// align-items: flex-start;
-// }
-
-// &:hover .type-display {
-// display: none;
-// }
-
-// .bubble {
-// margin: 5px;
-// }
-
-// &:hover .bubble {
-// margin-top: 7px;
-// }
-// }
-// }
-
-// .field-description-container {
-// background-color: rgb(40, 40, 40);
-// border: 1px solid rgb(100, 100, 100);
-// border-radius: 3px;
-// width: 100%;
-// height: 100%;
-// resize: none;
-
-// ::-webkit-scrollbar-track {
-// background: none;
-// }
-// }
-
-// .top-right {
-// position: absolute;
-// top: 0px;
-// right: 0px;
-// }
-// }
-// }
-
.field-panel {
display: flex;
flex-direction: column;
@@ -1214,4 +1061,127 @@
}
}
-} \ No newline at end of file
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+// EditingWindow CSS
+//--------------------------------------------------------------------------------------------------------------------------------------------
+
+.docCreatorMenu-editing-firefly-section {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ width: 100%;
+ padding: 5px;
+}
+
+.docCreatorMenu-firefly-options {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: flex-end;
+ height: fit-content;
+ width: 100%;
+}
+
+.docCreatorMenu-variation-prompt-row {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 15px;
+ height: fit-content;
+ width: 100%;
+}
+
+.docCreatorMenu-variation-prompt-input-textbox {
+ height: 40px;
+ width: 80%;
+ color: white;
+ margin-top: 1%;
+ margin-bottom: 1%;
+ margin-left: 5%;
+ background-color: rgb(50, 50, 50);
+ border-radius: 5px;
+ overflow: hidden;
+ resize: none;
+}
+
+.options‑menu {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 2rem;
+ padding: 0.5rem 1rem;
+ background: rgb(50, 50, 50);
+ color: whitesmoke;
+ font-family: system-ui, sans-serif;
+ font-size: 0.9rem;
+ flex-wrap: wrap;
+ }
+
+ .menu‑item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ white-space: nowrap;
+ }
+
+ .menu‑item input[type="range"] {
+ width: 7rem;
+ accent-color: whitesmoke;
+ }
+
+ .value {
+ min-width: 2ch;
+ text-align: right;
+ }
+
+ .switch {
+ gap: 0.75rem;
+ }
+
+ .switch .slider {
+ position: relative;
+ width: 2.2rem;
+ height: 1.1rem;
+ background: whitesmoke;
+ border-radius: 1rem;
+ cursor: pointer;
+ transition: background 0.2s;
+ }
+
+ .switch .slider::before {
+ content: '';
+ position: absolute;
+ top: 0.1rem;
+ left: 0.1rem;
+ width: 0.9rem;
+ height: 0.9rem;
+ background: rgb(50, 50, 50);
+ border-radius: 50%;
+ transition: transform 0.2s;
+ }
+
+ .switch input {
+ display: none;
+ }
+
+ .switch input:checked + .slider {
+ background: #9fe29d;
+ }
+
+ .switch input:checked + .slider::before {
+ transform: translateX(1.1rem);
+ }
+
+.firefly-option-label {
+ padding: .2em .6em .3em;
+ font-size: 100%;
+ color: whitesmoke;
+ text-align: center;
+}
+
+
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 2e4b81253..2565a9332 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -36,7 +36,7 @@ import { CgPathIntersect } from 'react-icons/cg';
import { StaticContentField } from './TemplateFieldTypes/StaticContentField';
import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils'
import { TemplatePreviewGrid } from './Menu/TemplatePreviewGrid';
-import { TemplateEditingWindow } from './Menu/TemplateEditingWindow';
+import { FireflyStructureOptions, TemplateEditingWindow } from './Menu/TemplateEditingWindow';
import { DocCreatorMenuButton } from './Menu/DocCreatorMenuButton';
export enum LayoutType {
@@ -103,7 +103,6 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
@observable _userCreatedFields: Col[] = [];
@observable _collapsedCols: String[] = []; //any columns whose options panels are hidden
- @observable _conditions: Conditional[] = [];
@observable _currEditingConditional: Conditional = {} as Conditional;
@observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 3, repeat: 0 };
@@ -594,7 +593,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
);
};
- generateVariations = async (onDoc: Doc, prompt: string): Promise<string[]> => {
+ generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions): Promise<string[]> => {
+ const { numVariations, temperature, useStyleRef } = options;
this.variations = [];
const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
@@ -603,12 +603,12 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
clone.x = 10000;
clone.y = 10000;
- await DrawingFillHandler.drawingToImage(clone, 100, prompt, clone, this)
+ await DrawingFillHandler.drawingToImage(clone, 100 - temperature, prompt, useStyleRef ? clone : undefined, this, numVariations)
return this.variations;
}
- @observable variations: string[] = []
+ variations: string[] = []
@action addVariation = (url: string) => {
this.variations.push(url);
@@ -918,7 +918,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
}
get dashboardContents() {
- const conditionForm = (title: string, parameters?: Conditional) => {
+ const conditionForm = (title: string, parameters?: Conditional, empty: boolean = false) => {
const params: Conditional = parameters ?? this._currEditingConditional;
@@ -942,8 +942,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
<div className='form-row-plain-text'>then</div>
<div className="operator-options-dropdown">
<span className="operator-dropdown-current">{params.target ?? 'self'}</span>
- <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'self'}}>{'self'}</div>
- <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'template'}}>{'template'}</div>
+ <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'self'}}>{'own'}</div>
+ <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'template'}}>{`template's`}</div>
</div>
<textarea
className="form-row-textarea"
@@ -959,17 +959,11 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
defaultValue={params.value}
/>
</div>
- <div className='form-action-button' onPointerDown={e => this.setUpButtonClick(e, runInAction(() => () => {
- if (this._currEditingConditional === params) {
- params.field = title;
- this._conditions.push(params);
- this._currEditingConditional = {} as Conditional;
- } else {
- this._conditions = this._conditions.filter(cond => cond !== params);
- }
- }))}>
- <FontAwesomeIcon icon={this._currEditingConditional === params ? 'plus' : 'minus'} color='white'/>
- </div>
+ {empty ?
+ <DocCreatorMenuButton icon={'plus'} styles={'float-right'} function={() => this.templateManager.addFieldCondition(title, params)}/>
+ :
+ <DocCreatorMenuButton icon={'minus'} styles={'float-right'} function={() => this.templateManager.removeFieldCondition(title, params)}/>
+ }
</div>
)
}
@@ -1030,8 +1024,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
</div>
<div className="conditionals-section">
<span className="conditionals-title">Conditional Logic</span>
- {conditionForm(field.title, this._currEditingConditional)}
- {this._conditions.map(condition => conditionForm(condition.field, condition))}
+ {conditionForm(field.title, this._currEditingConditional, true)}
+ {this.templateManager.conditionalFieldLogic[field.title]?.map(condition => conditionForm(condition.field, condition))}
</div>
</>
}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
index 0434d0ccb..4ff509d73 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable, reaction, runInAction } from "mobx";
+import { action, makeAutoObservable, makeObservable, observable, reaction, runInAction } from "mobx";
import React from "react";
import { returnFalse, returnEmptyFilter, returnTrue } from "../../../../../../ClientUtils";
import { emptyFunction } from "../../../../../../Utils";
@@ -16,93 +16,77 @@ import { ObservableReactComponent } from "../../../../ObservableReactComponent";
import { IDisposer } from "mobx-utils";
import { ImageField } from "../../../../../../fields/URLField";
import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
+import { TbHistory } from "react-icons/tb";
-interface TemplateEditingWindowProps {
+export type FireflyStructureOptions = {
+ numVariations: number;
+ temperature: number;
+ useStyleRef: boolean;
+}
+
+interface FireflyVariationsTabProps {
menu: DocCreatorMenu;
template: Template;
}
@observer
-export class TemplateEditingWindow extends ObservableReactComponent<TemplateEditingWindowProps> {
+export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariationsTabProps> {
- private fireflyPrompt: string = 'Use this template to generate an empty baseball card template.';
- private previewWindow: HTMLDivElement | null = null;
- private disposers: { [name: string]: IDisposer } = {};
- private promptInput: HTMLTextAreaElement | null = null;
+ private prompt: string = 'Use this template to generate an empty baseball card template.';
+
+ @observable private promptInput: HTMLTextAreaElement | null = null;
@observable _loading: boolean = false;
@observable _variationsTabOpen: boolean = false;
@observable _variationURLs: string[] = [];
- @observable _variations: Template[] = [];
-
- componentDidMount(): void {
- this.disposers.windowDimensions = reaction(() =>
- this._props.menu._resizing,
- () => { this.forceUpdate() },
- { fireImmediately: true }
- );
- }
-
- componentWillUnmount() {
- Object.values(this.disposers).forEach(disposer => disposer?.());
- }
-
- setPromptInputRef: React.LegacyRef<HTMLTextAreaElement> = (node) => {
- this.promptInput = node;
- this.forceUpdate();
- }
- setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
- this.previewWindow = node;
- this.forceUpdate();
- }
+ @observable private fireflyOptions: FireflyStructureOptions = {numVariations: 3, temperature: 0, useStyleRef: false};
- @action setVariationTab = (open: boolean) => {
- this._variationsTabOpen = open;
- if (this.previewWindow && open) {
- this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * .6);
- } else if (this.previewWindow && !open) {
- this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * 5/3);
- }
- this.forceUpdate();
+ constructor(props: FireflyVariationsTabProps) {
+ super(props);
+ makeObservable(this);
}
generateVariations = async () => {
this._props.menu._variations = [];
this._loading = true;
- this._variationURLs = await this._props.menu.generateVariations(this._props.template.clone(false).getRenderedDoc()!, this.fireflyPrompt);
+ const doc: Doc = this._props.template.clone(false).getRenderedDoc()!;
+ this._variationURLs = await this._props.menu.generateVariations(doc, this.prompt, this.fireflyOptions);
this._variationURLs.forEach(url => {
const newTemplate: Template = this._props.template.clone(true);
this._props.menu._variations.push(newTemplate);
});
- this._loading = false;
setTimeout(() => {
this._variationURLs.forEach((url, i) => {
this._props.menu._variations[i].setImageAsBackground(url, true);
});
- this.forceUpdate();
+ this._loading = false;
});
}
- get fireflyVariationsTab() {
+ setPromptInputRef: React.LegacyRef<HTMLTextAreaElement> = (node) => {
+ this.promptInput = node;
+ }
+ render() {
return (
- <>
+ <div className='docCreatorMenu-editing-firefly-section'>
<div className="docCreatorMenu-option-divider full no-margin-bottom"/>
<TemplatePreviewGrid
menu={this._props.menu}
title={'Generate Variations'}
loading={this._loading}
+ styles={'scrolling'}
templates={this._props.menu._variations}
optionsButtonOpts={['gear', () => {}]}
previewBoxRightButtonOpts={['gear', (template: Template) => {this.forceUpdate();}]}
/>
- <div className="docCreatorMenu-section">
- <div className="docCreatorMenu-variation-prompt-input">
+ <div className="docCreatorMenu-firefly-options">
+ <div className="docCreatorMenu-variation-prompt-row">
<textarea
className="docCreatorMenu-variation-prompt-input-textbox"
ref={this.setPromptInputRef}
- onChange={e => this.fireflyPrompt = e.target.value}
+ onChange={e => this.prompt = e.target.value}
onInput={() => {
if (this.promptInput !== null) {
this.promptInput.style.height = 'auto';
@@ -114,13 +98,84 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
/>
<DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations}/>
</div>
- <div className='docCreatorMenu-variation-options-container'>
-
- </div>
+ <nav className="options‑menu">
+ <div className="menu‑item switch">
+ <input type="checkbox" checked={this.fireflyOptions.useStyleRef}
+ onChange={(e) => runInAction(() => this.fireflyOptions.useStyleRef = e.target.checked)}
+ />
+ <span className="slider round"></span>
+ <span className="firefly-option-label">Use template as style guide</span>
+ </div>
+ <div className="menu‑item">
+ <span className="firefly-option-label">Variations</span>
+ <input type="range" id="variations"
+ min="1"
+ max="5"
+ value={this.fireflyOptions.numVariations}
+ onChange={(e) => runInAction(() => this.fireflyOptions.numVariations = Number(e.target.value))}
+ />
+ <span className="value" id="varVal">{this.fireflyOptions.numVariations}</span>
+ </div>
+ <div className="menu‑item">
+ <span className="firefly-option-label">Temperature</span>
+ <input type="range" id="temperature"
+ min="1"
+ max="100"
+ value={this.fireflyOptions.temperature}
+ onChange={(e) => runInAction(() => this.fireflyOptions.temperature = Number(e.target.value))}
+ />
+ <span className="value" id="tempVal">{this.fireflyOptions.temperature}</span>
+ </div>
+ </nav>
</div>
- </>
+ </div>
)
}
+}
+
+interface TemplateEditingWindowProps {
+ menu: DocCreatorMenu;
+ template: Template;
+}
+
+@observer
+export class TemplateEditingWindow extends ObservableReactComponent<TemplateEditingWindowProps> {
+
+ private disposers: { [name: string]: IDisposer } = {};
+
+ @observable private previewWindow: HTMLDivElement | null = null;
+
+ @observable _variationsTabOpen: boolean = false;
+
+ constructor(props: TemplateEditingWindowProps) {
+ super(props);
+ makeObservable(this);
+ }
+
+ componentDidMount(): void {
+ this.disposers.windowDimensions = reaction(() =>
+ this._props.menu._resizing,
+ () => { this.forceUpdate() },
+ { fireImmediately: true }
+ );
+ }
+
+ componentWillUnmount() {
+ Object.values(this.disposers).forEach(disposer => disposer?.());
+ }
+
+ setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
+ this.previewWindow = node;
+ }
+
+ @action setVariationTab = (open: boolean) => {
+ this._variationsTabOpen = open;
+ if (this.previewWindow && open) {
+ this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * .6);
+ } else if (this.previewWindow && !open) {
+ this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * 5/3);
+ }
+ }
get renderedDocPreview(){
const doc: Doc = this._props.template.getRenderedDoc() as unknown as Doc;
@@ -158,7 +213,11 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
<div className="docCreatorMenu-expanded-template-preview">
<div className="top-panel"/>
{this.renderedDocPreview}
- {this._variationsTabOpen ? this.fireflyVariationsTab : null}
+ {this._variationsTabOpen ? <FireflyVariationsTab
+ menu={this._props.menu}
+ template={this._props.template}
+ />
+ : null}
<div className="right-buttons-panel">
<DocCreatorMenuButton icon={'minimize'} function={() => {
if (this._props.template === this._props.menu._selectedTemplate) {
@@ -167,6 +226,7 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
this._props.menu.setExpandedView(undefined);
}}/>
<DocCreatorMenuButton icon={'lightbulb'} function={() => this.setVariationTab(!this._variationsTabOpen)}/>
+ <DocCreatorMenuButton icon={'arrow-rotate-backward'} function={() => { this._props.menu.setExpandedView(this._props.template); this.forceUpdate(); }}/>
</div>
</div>
</div>
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
index c9f817d2f..de2f9e455 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
@@ -1,7 +1,7 @@
import { Colors } from "@dash/components/src";
import { FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import { Template } from "../Template";
-import { reaction, runInAction } from "mobx";
+import { makeObservable, observable, reaction, runInAction } from "mobx";
import React from "react";
import { ObservableReactComponent } from "../../../../ObservableReactComponent";
import { DocCreatorMenu } from "../DocCreatorMenu";
@@ -17,7 +17,7 @@ import { ImageField } from "../../../../../../fields/URLField";
import { ImageCast } from "../../../../../../fields/Types";
import { observer } from "mobx-react";
-export interface TemplatePreviewBox_props {
+export interface TemplatePreviewBoxProps {
template: Template;
menu: DocCreatorMenu;
leftButtonOpts?: [icon: IconProp, func: (...args: any) => void]
@@ -25,32 +25,18 @@ export interface TemplatePreviewBox_props {
}
@observer
-export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreviewBox_props> {
+export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreviewBoxProps> {
- private previewWindow: HTMLDivElement | null = null;
- // private icon: ImageField | undefined = undefined;
+ @observable private previewWindow: HTMLDivElement | null = null;
setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
this.previewWindow = node;
- this.forceUpdate();
}
- // componentDidMount(): void {
- // console.log('mounted')
- // setTimeout(() => {
- // const docView = DocumentView.getDocumentView(this.doc);
- // if (docView) {
- // console.log('docview found')
- // docView.ComponentView?.updateIcon?.();
- // setTimeout(() => {
- // console.log('componentview found: ', docView.ComponentView)
- // this.icon = ImageCast(docView.Document.icon);
- // console.log('icon is:', this.icon, ' from: ', docView.Document.icon);
- // this.forceUpdate();
- // }, 5000);
- // }
- // }, 1000);
- // }
+ constructor(props: TemplatePreviewBoxProps) {
+ super(props);
+ makeObservable(this);
+ }
get doc() {
return this._props.template.getRenderedDoc() as Doc;
@@ -83,8 +69,6 @@ export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreview
<button className="option-button right" onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.rightButtonOpts![1](template))}>
<FontAwesomeIcon icon={this._props.rightButtonOpts![0]} color="white" />
</button> : null }
- {/* { this.icon ?
- <img className="docCreatorMenu-preview-image" src={this.icon.url.href.replace('.png', '_o.png')} /> */}
<DocumentView
Document={this.doc}
isContentActive={emptyFunction} // !!! should be return false
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
index 84ca6546d..d53853c52 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
@@ -1,6 +1,6 @@
import { Colors } from "@dash/components/src";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable, runInAction } from "mobx";
+import { action, makeObservable, observable, runInAction } from "mobx";
import React from "react";
import ReactLoading from "react-loading";
import { Doc } from "../../../../../../fields/Doc";
@@ -18,6 +18,7 @@ export interface SuggestedTemplatesProps {
loading?: boolean;
templates: Template[];
title: string;
+ styles?: string;
optionsButtonOpts?: [IconProp, (...args: any) => any];
previewBoxLeftButtonOpts?: [IconProp, (...args: any) => any];
previewBoxRightButtonOpts?: [IconProp, (...args: any) => any];
@@ -26,6 +27,11 @@ export interface SuggestedTemplatesProps {
@observer
export class TemplatePreviewGrid extends ObservableReactComponent<SuggestedTemplatesProps> {
+ constructor(props: SuggestedTemplatesProps) {
+ super(props);
+ makeObservable(this);
+ }
+
render() {
return (
<div className="docCreatorMenu-section">
@@ -35,7 +41,7 @@ export class TemplatePreviewGrid extends ObservableReactComponent<SuggestedTempl
<DocCreatorMenuButton icon={this._props.optionsButtonOpts[0] as IconProp} styles={'float-right'} function={() => runInAction(this._props.optionsButtonOpts![1])}/>
: null}
</div>
- <div className="docCreatorMenu-templates-preview-window">
+ <div className={"docCreatorMenu-templates-preview-window " + this._props.styles}>
{this._props.loading ?
(<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index 7ff521f18..fae0d06e4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -10,8 +10,6 @@ import { Doc } from '../../../../../fields/Doc';
export class Template {
_mainField: DynamicField;
- private conditionalLogic: Record<string, Conditional[]> = {};
-
/**
* A Template can be created from a description of its fields (FieldSettings) or from a DynamicField
* @param definition definition of template as settings or DynamicField
@@ -84,11 +82,11 @@ export class Template {
return maxMatches === this.contentFields.length && this.title !== 'template_framework';
};
- applyConditionalLogicToField = (field: TemplateField) => {
+ applyConditionalLogicToField = (field: TemplateField, logic: Record<string, Conditional[]>) => {
if (field instanceof DynamicField) return;
- const logic: Conditional[] = this.conditionalLogic[field.getTitle()];
+ const fieldStatements: Conditional[] = logic[field.getTitle()];
const content = field.getContent()
- logic && logic.forEach(statement => {
+ fieldStatements && fieldStatements.forEach(statement => {
if (content === statement.condition) {
if (statement.target === 'template') {
this._mainField.renderedDoc![statement.attribute] = statement.value;
@@ -99,17 +97,10 @@ export class Template {
})
}
- applyConditionalLogic = () => {
- const fields: TemplateField[] = [this._mainField, ...this.allFields];
- fields.forEach(this.applyConditionalLogicToField);
- }
-
- addConditionalStatement = (field: string, statement: Conditional) => {
- !this.conditionalLogic[field] ? this.conditionalLogic[field] = [statement] : this.conditionalLogic[field].push(statement);
- }
-
- removeConditionalStatement = (field: string, statement: Conditional) => {
- this.conditionalLogic[field] = this.conditionalLogic[field]?.filter(cond => cond !== statement);
+ applyConditionalLogic = (logic: Record<string, Conditional[]>) => {
+ console.log('applying logic: ', logic)
+ const fields: TemplateField[] = [...this.allFields];
+ fields.forEach(field => this.applyConditionalLogicToField(field, logic));
}
setImageAsBackground(url: string, makeTransparent: boolean = false) {
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index ad5ef7118..48107ff0d 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -15,7 +15,7 @@ import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, Firefl
const DashDropboxId = '2m86iveqdr9vzsa';
export class DrawingFillHandler {
- static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc, fromDocCreator?: DocCreatorMenu) => {
+ static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc, fromDocCreator?: DocCreatorMenu, numVariations: number = 4) => {
const docData = drawing[DocData];
const tags = StrListCast(docData.tags).map(tag => tag.slice(1));
const styles = tags.filter(tag => FireflyStylePresets.has(tag));
@@ -45,9 +45,8 @@ export class DrawingFillHandler {
return imageUrlToBase64(structureUrl)
.then(gptDescribeImage)
.then((prompt, newPrompt = user_prompt || prompt) =>
- Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl })
+ Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl, variations: numVariations})
.then(res => {
- console.log('res is: ', res)
const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { _width: 400, _height: 400 });
drawing[DocData].ai_firefly_generatedDocs = genratedDocs;
(res as Upload.ImageInformation[]).map(info => {
diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts
index e5e030b0f..a272494b8 100644
--- a/src/server/ApiManagers/FireflyManager.ts
+++ b/src/server/ApiManagers/FireflyManager.ts
@@ -22,7 +22,7 @@ export default class FireflyManager extends ApiManager {
return undefined;
});
- generateImageFromStructure = (prompt: string = 'a realistic illustration of a cat coding', width: number = 2048, height: number = 2048, structureUrl: string, strength: number = 50, styles: string[], styleUrl: string | undefined) =>
+ generateImageFromStructure = (prompt: string = 'a realistic illustration of a cat coding', width: number = 2048, height: number = 2048, structureUrl: string, strength: number = 50, styles: string[], styleUrl: string | undefined, variations: number = 4) =>
this.getBearerToken().then(response =>
response?.json().then((data: { access_token: string }) =>
//prettier-ignore
@@ -36,7 +36,7 @@ export default class FireflyManager extends ApiManager {
],
body: JSON.stringify({
prompt,
- numVariations: 4,
+ numVariations: variations,
detailLevel: 'preview',
modelVersion: 'image3_fast',
size: { width, height },
@@ -308,7 +308,7 @@ export default class FireflyManager extends ApiManager {
return { styleUrl, structureUrl: dropboxStructureUrl };
})
.then(uploads =>
- this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploads.structureUrl, req.body.strength, req.body.presets, uploads.styleUrl)
+ this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploads.structureUrl, req.body.strength, req.body.presets, uploads.styleUrl, req.body.variations)
.then(images => {
Promise.all((images ?? [new Error('no images were generated')]).map(fire => (fire instanceof Error ? fire : DashUploadUtils.UploadImage(fire.url))))
.then(dashImages => {