aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/TabDocView.tsx4
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts79
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts34
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss183
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx206
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx277
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx252
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx113
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx97
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts132
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts7
-rw-r--r--src/client/views/nodes/ImageBox.tsx1
12 files changed, 621 insertions, 764 deletions
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index c4373aaa7..897a86e7f 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -584,9 +584,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
miniMapColor = () => Colors.MEDIUM_GRAY;
tabView = () => this._view;
disableMinimap = () => !this._document;
- whenChildContentActiveChanges = (isActive: boolean) => {
- this._isAnyChildContentActive = isActive;
- };
+ whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
isContentActiveFunc = () => this.isContentActive;
waitForDoubleClick = () => (SnappingManager.ExploreMode ? 'never' : undefined);
renderDocView = (doc: Doc) => (
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
index 78235d000..526fcf9c4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
@@ -14,87 +14,64 @@ export type Conditional = {
target: string;
attribute: string;
value: string;
-}
+};
export class TemplateManager {
+ _templates: Template[] = [];
- templates: Template[] = [];
-
- conditionalFieldLogic: Record<string, Conditional[]> = {};
+ _conditionalFieldLogic: Record<string, Conditional[]> = {};
constructor(templateSettings: FieldSettings[]) {
makeAutoObservable(this);
- this.templates = this.initializeTemplates(templateSettings);
+ this._templates = templateSettings.map(settings => new Template(settings));
}
- initializeTemplates = (templateSettings: FieldSettings[]) => templateSettings.map(settings => {
- return new Template(settings)});
-
- getValidTemplates = (cols: Col[]) => this.templates.filter(template => template.isValidTemplate(cols));
+ getValidTemplates = (cols: Col[]) => this._templates.filter(template => template.isValidTemplate(cols));
- addTemplate = (newTemplate: Template) => this.templates.push(newTemplate);
+ addTemplate = (newTemplate: Template) => this._templates.push(newTemplate);
removeTemplate = (template: Template) => {
- this.templates.splice(this.templates.indexOf(template), 1);
+ if (this._templates.includes(template)) {
+ this._templates.splice(this._templates.indexOf(template), 1);
+ }
template.cleanup();
};
addFieldCondition = (fieldTitle: string, condition: Conditional) => {
- if (this.conditionalFieldLogic[fieldTitle] === undefined) {
- this.conditionalFieldLogic[fieldTitle] = [condition];
+ if (this._conditionalFieldLogic[fieldTitle] === undefined) {
+ this._conditionalFieldLogic[fieldTitle] = [condition];
} else {
- this.conditionalFieldLogic[fieldTitle].push(condition);
+ this._conditionalFieldLogic[fieldTitle].push(condition);
}
- }
+ };
- removeFieldCondition = (fieldTitle: string, condition: Conditional) => {
- if (this.conditionalFieldLogic[fieldTitle]) {
- this.conditionalFieldLogic[fieldTitle] = this.conditionalFieldLogic[fieldTitle].filter(cond => cond !== condition);
- }
- }
+ removeFieldCondition = (fieldTitle: string, condition: Conditional) => (this._conditionalFieldLogic[fieldTitle] = this._conditionalFieldLogic[fieldTitle]?.filter(cond => cond !== condition));
- addDataField = (title: string) => {
- this.templates.forEach(template => template.addDataField(title));
- }
+ addDataField = (title: string) => this._templates.forEach(template => template.addDataField(title));
- removeDataField = (title: string) => {
- this.templates.forEach(template => template.removeDataField(title));
- }
+ removeDataField = (title: string) => this._templates.forEach(template => template.removeDataField(title));
createDocsFromTemplate = action((dv: DataVizBox, template: Template, cols: Col[], debug: boolean = false) => {
const csvFields = Array.from(Object.keys(dv.records[0]));
- const processContent = async (content: { [title: string]: string }) => {
+ const processContent = (content: { [title: string]: string }) => {
const templateCopy = template.clone();
csvFields
.filter(title => title)
.forEach(title => {
const field = templateCopy.getFieldByTitle(title);
- field && field.setContent(content[title], field.viewType);
+ field?.setContent(content[title], field.viewType);
});
const gptFunc = (type: TemplateFieldType) => (type === TemplateFieldType.VISUAL ? TemplateMenuAIUtils.renderGPTImageCall : TemplateMenuAIUtils.renderGPTTextCall);
- const applyGPTContent = async () => {
- const promises = cols
- .filter(field => field.AIGenerated)
- .map(field => {
- const templateField: TemplateField = templateCopy.getFieldByTitle(field.title) as TemplateField;
- if (templateField !== undefined) {
- return gptFunc(field.type)(templateCopy, field, templateField.getID);
- }
- return null;
- })
- .filter(p => p !== null);
-
- await Promise.all(promises);
- };
-
- await applyGPTContent();
-
- templateCopy.applyConditionalLogic(this.conditionalFieldLogic);
-
- return templateCopy.getRenderedDoc();
+
+ const generateGptContent = cols
+ .map(field => ({ field, templateField: field?.AIGenerated && templateCopy.getFieldByTitle(field.title) }))
+ .filter(({ templateField }) => templateField instanceof TemplateField)
+ .map(({ field, templateField }) => gptFunc(field.type)(templateCopy, field, (templateField as TemplateField).getID));
+
+ return Promise.all(generateGptContent).then(() => templateCopy.applyConditionalLogic(this._conditionalFieldLogic));
};
const rowContents = debug
@@ -109,10 +86,6 @@ export class TemplateManager {
)
);
- return Promise.all(rowContents.map(processContent)).then(
- action(renderedDocs => {
- return renderedDocs;
- })
- );
+ return Promise.all(rowContents.map(processContent));
});
}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
index 162b7a1b1..08818dd6c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
@@ -1,13 +1,13 @@
-import { ClientUtils } from "../../../../../../ClientUtils";
-import { Networking } from "../../../../../Network";
-import { gptImageCall, gptAPICall, GPTCallType } from "../../../../../apis/gpt/GPT";
-import { Col } from "../DocCreatorMenu";
-import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
-import { TemplateField, ViewType } from "../TemplateFieldTypes/TemplateField";
-import { Template } from "../Template";
+import { ClientUtils } from '../../../../../../ClientUtils';
+import { Networking } from '../../../../../Network';
+import { gptImageCall, gptAPICall, GPTCallType } from '../../../../../apis/gpt/GPT';
+import { Col } from '../DocCreatorMenu';
+import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
+import { ViewType } from '../TemplateFieldTypes/TemplateField';
+import { Template } from '../Template';
+import { Upload } from '../../../../../../server/SharedMediaTypes';
export class TemplateMenuAIUtils {
-
public static generateGPTImage = async (prompt: string): Promise<string | undefined> => {
try {
const res = await gptImageCall(prompt);
@@ -24,13 +24,10 @@ export class TemplateMenuAIUtils {
public static renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
const generateAndLoadImage = async (id: number, prompt: string) => {
+ const field = template.getFieldByID(id);
const url = await this.generateGPTImage(prompt);
- // eslint-disable-next-line
- var field: TemplateField = template.getFieldByID(id);
-
- field.setContent(url ?? '', ViewType.IMG);
- field = template.getFieldByID(id);
- field.setTitle(col.title);
+ field?.setContent(url ?? '', ViewType.IMG);
+ field?.setTitle(col.title);
};
const fieldContent: string = template.compiledContent;
@@ -81,10 +78,10 @@ export class TemplateMenuAIUtils {
if (res) {
const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
Object.entries(assignments).forEach(([, /* title */ info]) => {
- const field: TemplateField = template.getFieldByID(Number(info.number));
+ const field = template.getFieldByID(Number(info.number));
- field.setContent(info.content ?? '', ViewType.TEXT);
- field.setTitle(col.title);
+ field?.setContent(info.content ?? '', ViewType.TEXT);
+ field?.setTitle(col.title);
});
}
} catch (err) {
@@ -122,5 +119,4 @@ export class TemplateMenuAIUtils {
return template;
};
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index 463e69c67..6eb7fa96a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -9,10 +9,10 @@
position: absolute;
z-index: 1000;
// box-shadow: 0px 3px 4px rgba(0, 0, 0, 30%);
- // background: whitesmoke;
+ // background: whitesmoke;
// color: black;
border-radius: 3px;
-}
+}
.docCreatorMenu-menu {
display: flex;
@@ -24,7 +24,7 @@
.docCreatorMenu-menu-button {
width: 25px;
height: 25px;
- background: whitesmoke;
+ background: whitesmoke;
background-color: rgb(50, 50, 50);
border-radius: 5px;
padding: 0px;
@@ -53,8 +53,8 @@
position: absolute;
right: 0px;
}
-
- &.right{
+
+ &.right {
margin-left: 0px;
font-size: 12px;
}
@@ -103,12 +103,12 @@
}
}
- &:hover::before{
+ &:hover::before {
border-bottom: 20px solid rgb(82, 82, 82);
}
&::before {
- content: "";
+ content: '';
position: absolute;
top: 0;
left: 0;
@@ -120,7 +120,7 @@
}
&::after {
- content: "";
+ content: '';
position: absolute;
top: -1px;
left: -1px;
@@ -143,7 +143,7 @@
color: white;
}
-.docCreatorMenu-menu-hr{
+.docCreatorMenu-menu-hr {
margin-top: 0px;
margin-bottom: 0px;
color: rgb(180, 180, 180);
@@ -173,14 +173,14 @@
align-items: center;
width: 40px;
height: 40px;
- background-color: rgb(99, 148, 238);
+ background-color: rgb(99, 148, 238);
border: 2px solid rgb(80, 107, 152);
border-radius: 5px;
margin-bottom: 20px;
font-size: 25px;
- &:hover{
- background-color: rgb(59, 128, 255);
+ &:hover {
+ background-color: rgb(59, 128, 255);
border: 2px solid rgb(53, 80, 127);
}
}
@@ -188,7 +188,7 @@
.docCreatorMenu-create-docs-button {
width: 40px;
height: 40px;
- background-color: rgb(176, 229, 149);
+ background-color: rgb(176, 229, 149);
border: 2px solid rgb(126, 219, 80);
border-radius: 5px;
padding: 0px;
@@ -199,7 +199,7 @@
&:hover {
background-color: rgb(129, 223, 83);
- border: 2px solid rgb(80, 185, 28);
+ border: 2px solid rgb(80, 185, 28);
}
}
@@ -230,17 +230,22 @@
position: absolute;
background-color: none;
- &.top, &.bottom {
+ &.top,
+ &.bottom {
height: 10px;
cursor: ns-resize;
}
- &.right, &.left {
+ &.right,
+ &.left {
width: 10px;
cursor: ew-resize;
}
- &.topRight, &.topLeft, &.bottomRight, &.bottomLeft {
+ &.topRight,
+ &.topLeft,
+ &.bottomRight,
+ &.bottomLeft {
height: 15px;
width: 15px;
background-color: none;
@@ -263,7 +268,7 @@
height: calc(100% - 30px);
border: 1px solid rgb(180, 180, 180);
border-radius: 5px;
- -ms-overflow-style: none;
+ -ms-overflow-style: none;
scrollbar-width: none;
}
@@ -277,7 +282,7 @@
height: 100%;
flex-grow: 1;
- .top-panel{
+ .top-panel {
width: 100%;
height: 10px;
}
@@ -302,13 +307,14 @@
justify-content: center;
align-items: center;
height: 100%;
+ width: 100%;
aspect-ratio: 1;
color: none;
border: 1px solid rgb(163, 163, 163);
border-radius: 5px;
box-shadow: 5px 5px rgb(29, 29, 31);
- &:hover{
+ &:hover {
background-color: rgb(72, 72, 73);
}
@@ -353,20 +359,18 @@
&:hover .option-button {
display: block;
}
-
}
-.docCreatorMenu-preview-image{
+.docCreatorMenu-preview-image {
background-color: transparent;
height: 100%;
display: block;
object-fit: contain;
border-radius: 5px;
-
}
.docCreatorMenu-variations-tab {
- flex-grow: .5;
+ flex-grow: 0.5;
}
.docCreatorMenu-section {
@@ -400,7 +404,7 @@
display: grid;
justify-content: space-evenly;
row-gap: 2rem;
- grid-template-columns: repeat(auto-fill, minmax(150px, 30%));
+ grid-template-columns: repeat(auto-fill, minmax(150px, 50%));
margin: 5px;
width: calc(100% - 10px);
height: 100%;
@@ -413,7 +417,7 @@
}
}
-.divvv{
+.div {
width: 200;
height: 200;
border: solid 1px white;
@@ -448,7 +452,7 @@
.docCreatorMenu-GPT-generate {
height: 30px;
width: 30px;
- background-color: rgb(176, 229, 149);
+ background-color: rgb(176, 229, 149);
border: 1px solid rgb(126, 219, 80);
border-radius: 5px;
padding: 0px;
@@ -459,7 +463,7 @@
&:hover {
background-color: rgb(129, 223, 83);
- border: 2px solid rgb(80, 185, 28);
+ border: 2px solid rgb(80, 185, 28);
}
}
@@ -477,7 +481,7 @@
// DocCreatorMenu options CSS
//--------------------------------------------------------------------------------------------------------------------------------------------
-.docCreatorMenu-option-container{
+.docCreatorMenu-option-container {
display: flex;
width: 180px;
height: 30px;
@@ -487,16 +491,16 @@
margin-top: 10px;
margin-bottom: 10px;
- &.layout{
+ &.layout {
z-index: 5;
}
}
-.docCreatorMenu-option-title{
+.docCreatorMenu-option-title {
display: flex;
width: 140px;
height: 30px;
- background: whitesmoke;
+ background: whitesmoke;
background-color: rgb(34, 34, 37);
border-radius: 5px;
border: 1px solid rgb(180, 180, 180);
@@ -513,7 +517,7 @@
border-radius: 0px;
width: auto;
text-transform: none;
-
+
&.small {
height: 20px;
transform: translateY(-5px);
@@ -607,38 +611,38 @@
height: calc(100% - 30px);
border: 1px solid rgb(180, 180, 180);
border-radius: 5px;
- -ms-overflow-style: none;
+ -ms-overflow-style: none;
scrollbar-width: none;
- .docCreatorMenu-option-container{
+ .docCreatorMenu-option-container {
width: 180px;
height: 30px;
.docCreatorMenu-dropdown-hoverable {
width: 140px;
height: 30px;
-
+
&:hover .docCreatorMenu-dropdown-content {
display: block;
}
-
+
&:hover .docCreatorMenu-option-title {
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
-
+
.docCreatorMenu-dropdown-content {
display: none;
min-width: 100px;
height: 75px;
overflow-y: scroll;
- -ms-overflow-style: none;
+ -ms-overflow-style: none;
scrollbar-width: none;
border-bottom: 1px solid rgb(180, 180, 180);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
-
- .docCreatorMenu-dropdown-option{
+
+ .docCreatorMenu-dropdown-option {
display: flex;
background-color: rgb(42, 42, 46);
border-left: 1px solid rgb(180, 180, 180);
@@ -649,13 +653,13 @@
justify-content: center;
justify-items: center;
padding-top: 3px;
-
+
&:hover {
background-color: rgb(68, 68, 74);
cursor: pointer;
}
}
- }
+ }
}
}
}
@@ -710,7 +714,7 @@
border: 1px solid rgb(180, 180, 180);
border-radius: 5px;
background-color: rgb(34, 34, 37);
- -ms-overflow-style: none;
+ -ms-overflow-style: none;
scrollbar-width: none;
&.small {
@@ -742,10 +746,10 @@
z-index: 999;
}
- .docCreatorMenu-zoom-button{
+ .docCreatorMenu-zoom-button {
width: 15px;
height: 15px;
- background: whitesmoke;
+ background: whitesmoke;
background-color: rgb(34, 34, 37);
border-radius: 3px;
border: 1px solid rgb(180, 180, 180);
@@ -759,8 +763,6 @@
}
}
-
-
//------------------------------------------------------------------------------------------------------------------------------------------
// DocCreatorMenu dashboard CSS
//--------------------------------------------------------------------------------------------------------------------------------------------
@@ -778,7 +780,7 @@
height: calc(100% - 30px);
border: 1px solid rgb(180, 180, 180);
border-radius: 5px;
- -ms-overflow-style: none;
+ -ms-overflow-style: none;
scrollbar-width: none;
.panels-container {
@@ -836,8 +838,8 @@
background-color: rgb(72, 72, 72);
cursor: pointer;
}
- }
-
+ }
+
.opts-bar {
display: flex;
flex-direction: row;
@@ -880,11 +882,11 @@
flex-direction: row;
align-items: flex-start;
}
-
+
&:hover .type-display {
display: none;
}
-
+
.bubble {
margin: 3px;
}
@@ -919,7 +921,7 @@
flex-direction: row;
align-items: center;
}
-
+
.bubble {
margin: 3px;
margin-right: 4px;
@@ -942,10 +944,8 @@
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
resize: none;
-
}
}
-
}
.conditionals-section {
@@ -972,7 +972,7 @@
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
- color: whitesmoke;
+ color: whitesmoke;
width: 100%;
height: fit-content;
margin-bottom: 15px;
@@ -1041,7 +1041,6 @@
overflow-y: scroll;
white-space: nowrap;
}
-
}
.form {
@@ -1057,10 +1056,8 @@
align-items: center;
margin: 3px;
cursor: pointer;
-
}
}
-
}
//------------------------------------------------------------------------------------------------------------------------------------------
@@ -1113,38 +1110,38 @@
display: flex;
align-items: center;
justify-content: center;
- gap: 2rem;
+ 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 {
+ flex-wrap: wrap;
+}
+
+.menu‑item {
display: flex;
align-items: center;
gap: 0.5rem;
white-space: nowrap;
- }
-
- .menu‑item input[type="range"] {
+}
+
+.menu‑item input[type='range'] {
width: 7rem;
- accent-color: whitesmoke;
- }
-
- .value {
+ accent-color: whitesmoke;
+}
+
+.value {
min-width: 2ch;
text-align: right;
- }
-
- .switch {
+}
+
+.switch {
gap: 0.75rem;
margin-bottom: 0px;
- }
-
- .switch .slider {
+}
+
+.switch .slider {
position: relative;
width: 2.2rem;
height: 1.1rem;
@@ -1152,9 +1149,9 @@
border-radius: 1rem;
cursor: pointer;
transition: background 0.2s;
- }
-
- .switch .slider::before {
+}
+
+.switch .slider::before {
content: '';
position: absolute;
top: 0.1rem;
@@ -1164,27 +1161,25 @@
background: rgb(50, 50, 50);
border-radius: 50%;
transition: transform 0.2s;
- }
-
- .switch input {
+}
+
+.switch input {
display: none;
- }
-
- .switch input:checked + .slider {
+}
+
+.switch input:checked + .slider {
background: #78c2f1;
- }
-
- .switch input:checked + .slider::before {
+}
+
+.switch input:checked + .slider::before {
transform: translateX(1.1rem);
- }
+}
.firefly-option-label {
- padding: .2em .6em .3em;
+ padding: 0.2em 0.6em 0.3em;
font-size: 100%;
color: whitesmoke;
text-align: center;
margin-bottom: 0px;
font-weight: 500;
}
-
-
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index ebfa3fc65..fb083ea75 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -1,4 +1,3 @@
-
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
@@ -22,7 +21,7 @@ import { ViewType } from './TemplateFieldTypes/TemplateField';
import { Template } from './Template';
import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
import { TemplateManager } from './Backend/TemplateManager';
-import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils'
+import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils';
import { TemplatePreviewGrid } from './Menu/TemplatePreviewGrid';
import { FireflyStructureOptions, TemplateEditingWindow } from './Menu/TemplateEditingWindow';
import { DocCreatorMenuButton } from './Menu/DocCreatorMenuButton';
@@ -158,18 +157,12 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
return bounds;
}
- setUpButtonClick = (e: React.PointerEvent, func: (...args: any) => void) => {
- setupMoveUpEvents(
- this,
- e,
- returnFalse,
- emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- clickEv.preventDefault();
- func();
- }, 'create docs')
- );
+ setUpButtonClick = (e: React.PointerEvent, func: () => void) => {
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => {
+ clickEv.stopPropagation();
+ clickEv.preventDefault();
+ undoable(func, 'create docs')();
+ });
};
@action
@@ -301,16 +294,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
this._pageX = x + translation.x;
this._pageY = y + translation.y;
};
-
- async createDocsForPreview(): Promise<Doc[]> { return this._dataViz && this._selectedTemplate ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, this._selectedTemplate, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) as unknown as Doc[] : []; }
- @action updateSelectedTemplate = async (template: Template) => {
- if (this._selectedTemplate === template) {
- this._selectedTemplate = undefined;
- return;
- } else {
- this._selectedTemplate = template;
- }
+ async createDocsForPreview() {
+ return this._dataViz && this._selectedTemplate ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, this._selectedTemplate, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) : [];
+ }
+
+ @action updateSelectedTemplate = (template: Template) => {
+ this._selectedTemplate = this._selectedTemplate === template ? undefined : template; // toggle selection
};
// testTemplate = async () => {
@@ -318,27 +308,16 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
// };
@action addField = () => {
- const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [], AIGenerated: true }]);
- this._userCreatedFields = newFields;
+ this._userCreatedFields = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [], AIGenerated: true }]);
};
@action removeField = (field: { title: string; type: string; desc: string }) => {
if (this._dataViz?.axes.includes(field.title)) {
this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title));
} else {
- const toRemove = this._userCreatedFields.filter(f => f === field);
- if (!toRemove) return;
-
- if (toRemove.length > 1) {
- while (toRemove.length > 1) {
- toRemove.pop();
- }
- }
-
- if (this._userCreatedFields.length === 1) {
- this._userCreatedFields = [];
- } else {
- this._userCreatedFields.splice(this._userCreatedFields.indexOf(toRemove[0]), 1);
+ const toRemove = this._userCreatedFields.findIndex(f => f === field);
+ if (toRemove !== -1) {
+ this._userCreatedFields.splice(toRemove, 1);
}
}
};
@@ -390,35 +369,22 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
this.forceUpdate();
};
- compileFieldDescriptions = (templates: Template[]): string => {
- let descriptions: string = '';
- templates.forEach(template => {
- descriptions += `---------- NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: `;
- descriptions += template.descriptionSummary;
- });
-
- return descriptions;
- };
-
- compileColDescriptions = (cols: Col[]): string => {
- let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:';
- cols.forEach(col => (descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `));
+ compileFieldDescriptions = (templates: Template[]) =>
+ templates.map(template => `---------- NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: ` + template.descriptionSummary).join(''); // prettier-ignore
- return descriptions;
- };
+ compileColDescriptions = (cols: Col[]) =>
+ ' ------------- COL DESCRIPTIONS START HERE:' + cols.map(col => `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `).join(''); // prettier-ignore
- getColByTitle = (title: string) => {
- return this.fieldsInfos.filter(col => col.title === title)[0];
- };
+ getColByTitle = (title: string): Col | undefined => this.fieldsInfos.filter(col => col.title === title)[0];
@action
assignColsToFields = async (templates: Template[], cols: Col[]): Promise<[Template, { [field: number]: Col }][]> => {
- const fieldDescriptions: string = this.compileFieldDescriptions(templates);
- const colDescriptions: string = this.compileColDescriptions(cols);
+ const fieldDescriptions = this.compileFieldDescriptions(templates);
+ const colDescriptions = this.compileColDescriptions(cols);
const inputText = fieldDescriptions.concat(colDescriptions);
- const prompt: string = `(${Math.random() * 100000}) ${inputText}`;
+ const prompt = `(${Math.random() * 100000}) ${inputText}`;
this._GPTLoading = true;
@@ -431,23 +397,25 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
Object.entries(assignments).forEach(([tempTitle, assignment]) => {
const template = templates.filter(temp => temp.title === tempTitle)[0];
- if (!template) return;
- const toObj = Object.entries(assignment).reduce(
- (a, [fieldID, colTitle]) => {
- const col = this.getColByTitle(colTitle);
- if (!col.AIGenerated) {
- var field = template.getFieldByID(Number(fieldID));
- field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
- field = template.getFieldByID(Number(fieldID));
- field.setTitle(col.title);
- } else {
- a[Number(fieldID)] = this.getColByTitle(colTitle);
- }
- return a;
- },
- {} as { [field: number]: Col }
- );
- brokenDownAssignments.push([template, toObj]);
+ if (template) {
+ const toObj = Object.entries(assignment).reduce(
+ (a, [fieldID, colTitle]) => {
+ const col = this.getColByTitle(colTitle);
+ if (col) {
+ if (!col.AIGenerated) {
+ const field = template.getFieldByID(Number(fieldID));
+ field?.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+ field?.setTitle(col.title);
+ } else {
+ a[Number(fieldID)] = col;
+ }
+ }
+ return a;
+ },
+ {} as { [field: number]: Col }
+ );
+ brokenDownAssignments.push([template, toObj]);
+ }
});
return brokenDownAssignments;
@@ -459,39 +427,32 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
return [];
};
- generatePresetTemplates = async () => {
- const templates: Template[] = [];
-
+ generatePresetTemplates = action(() => {
if (this.DEBUG_MODE) {
- templates.push(...this.templateManager.templates);
+ this.setSuggestedTemplates(this.templateManager._templates);
+ this._GPTLoading = false;
} else {
this._dataViz?.updateColDefaults();
-
const contentFields = this.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA);
-
- templates.push(...this.templateManager.getValidTemplates(contentFields));
-
- const assignments = await this.assignColsToFields(templates, contentFields);
-
- const renderedTemplatePromises = assignments.map(([template, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(template, assgns));
-
- await Promise.all(renderedTemplatePromises);
+ const templates = this.templateManager.getValidTemplates(contentFields);
+
+ return this.assignColsToFields(templates, contentFields)
+ .then(pairs =>
+ Promise.all(pairs.map(([templ, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(templ, assgns))))
+ .then(action(() => {
+ this.setSuggestedTemplates(templates);
+ this._GPTLoading = false;
+ })); // prettier-ignore
}
+ });
- setTimeout(
- action(() => {
- this.setSuggestedTemplates(templates);
- this._GPTLoading = false;
- })
- );
- };
-
- generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions): Promise<string[]> => {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions) => {
// const { numVariations, temperature, useStyleRef } = options;
this.variations = [];
const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
- const clone: Doc = (await Doc.MakeClone(onDoc)).clone;
+ const clone = Doc.MakeClone(onDoc).clone;
mainCollection.addDocument(clone);
clone.x = 10000;
clone.y = 10000;
@@ -499,13 +460,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
// await DrawingFillHandler.drawingToImage(clone, 100 - temperature, prompt, useStyleRef ? clone : undefined, this, numVariations)
return this.variations;
- }
+ };
- variations: string[] = []
+ variations: string[] = [];
@action addVariation = (url: string) => {
this.variations.push(url);
- }
+ };
addRenderedCollectionToMainview = (collection: Doc) => {
if (collection) {
@@ -517,10 +478,11 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
}
};
- @action editLastTemplate = () => { if (this._editedTemplateTrail.length) this._currEditingTemplate = this._editedTemplateTrail.pop()}
+ @action editLastTemplate = () => {
+ if (this._editedTemplateTrail.length) this._currEditingTemplate = this._editedTemplateTrail.pop();
+ };
@action setExpandedView = (template: Template | undefined) => {
-
if (template) {
this._menuContent = 'templateEditing';
this._currEditingTemplate && this._editedTemplateTrail.push(this._currEditingTemplate);
@@ -533,27 +495,23 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
//Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
};
- @computed
- get templatesView() { return (
- <div className='docCreatorMenu-templates-view'>
- <div className="docCreatorMenu-templates-displays">
- <TemplatePreviewGrid
- title={'Suggested Templates'}
- menu={this}
- loading={this._GPTLoading}
- optionsButtonOpts={this.optionsButtonOpts}
- templates={this._suggestedTemplates}
- />
- <div className="docCreatorMenu-GPT-options">
- <div className="docCreatorMenu-GPT-options-container">
- <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generatePresetTemplates}/>
+ @computed
+ get templatesView() {
+ return (
+ <div className="docCreatorMenu-templates-view">
+ <div className="docCreatorMenu-templates-displays">
+ <TemplatePreviewGrid title={'Suggested Templates'} menu={this} loading={this._GPTLoading} optionsButtonOpts={this.optionsButtonOpts} templates={this._suggestedTemplates} />
+ <div className="docCreatorMenu-GPT-options">
+ <div className="docCreatorMenu-GPT-options-container">
+ <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generatePresetTemplates} />
+ </div>
</div>
</div>
</div>
- </div>
- )};
-
- private optionsButtonOpts: [IconProp, () => any] = ['gear', () => (this._menuContent = 'dashboard')];
+ );
+ }
+
+ private optionsButtonOpts: [IconProp, () => void] = ['gear', () => (this._menuContent = 'dashboard')];
get renderSelectedViewType() {
switch (this._menuContent) {
@@ -634,7 +592,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
{topButton('magnifying-glass', 'options', onOptionsSelected, 'middle')}
{topButton('bars', 'saved', onSavedSelected, 'right')}
</div>
- <DocCreatorMenuButton icon={'minus'} styles={'float-right'} function={this.closeMenu}/>
+ <DocCreatorMenuButton icon={'minus'} styles={'float-right'} function={this.closeMenu} />
</div>
{this.renderSelectedViewType}
</div>
@@ -642,4 +600,4 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
index b50fff9e0..c35099e82 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
@@ -1,25 +1,25 @@
-import { action, makeObservable, observable, reaction, runInAction } from "mobx";
-import React from "react";
-import { returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
-import { emptyFunction } from "../../../../../../Utils";
-import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { DocumentView, DocumentViewInternal } from "../../../DocumentView";
-import { DocCreatorMenu } from "../DocCreatorMenu";
-import { TemplatePreviewGrid } from "./TemplatePreviewGrid";
-import { observer } from "mobx-react";
-import { Transform } from "../../../../../util/Transform";
-import { Template } from "../Template";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { IDisposer } from "mobx-utils";
-import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { action, makeObservable, observable, reaction } from 'mobx';
+import React from 'react';
+import { returnFalse, returnEmptyFilter } from '../../../../../../ClientUtils';
+import { emptyFunction } from '../../../../../../Utils';
+import { returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { DocumentView, DocumentViewInternal } from '../../../DocumentView';
+import { DocCreatorMenu } from '../DocCreatorMenu';
+import { TemplatePreviewGrid } from './TemplatePreviewGrid';
+import { observer } from 'mobx-react';
+import { Transform } from '../../../../../util/Transform';
+import { Template } from '../Template';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { IDisposer } from 'mobx-utils';
+import { DocCreatorMenuButton } from './DocCreatorMenuButton';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
export type FireflyStructureOptions = {
numVariations: number;
temperature: number;
useStyleRef: boolean;
-}
+};
interface FireflyVariationsTabProps {
menu: DocCreatorMenu;
@@ -28,112 +28,93 @@ interface FireflyVariationsTabProps {
@observer
export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariationsTabProps> {
+ private _prompt: string = 'Use this template to generate an empty baseball card template.';
+ private _optionsButtonOpts: [IconProp, () => void] = ['gear', emptyFunction];
+ private _previewBoxRightButtonOpts: [IconProp, () => void] = ['gear', () => this.forceUpdate()];
- private prompt: string = 'Use this template to generate an empty baseball card template.';
-
- @observable private promptInput: HTMLTextAreaElement | null = null;
-
+ @observable _fireflyOptions: FireflyStructureOptions = { numVariations: 3, temperature: 0, useStyleRef: false };
+ @observable _promptInput: HTMLTextAreaElement | null = null;
@observable _loading: boolean = false;
@observable _variationsTabOpen: boolean = false;
@observable _variationURLs: string[] = [];
- @observable private fireflyOptions: FireflyStructureOptions = {numVariations: 3, temperature: 0, useStyleRef: false};
-
constructor(props: FireflyVariationsTabProps) {
super(props);
makeObservable(this);
}
- generateVariations = async () => {
+ generateVariations = action(async () => {
this._props.menu._variations = [];
this._loading = true;
const cloneTemplate = this._props.template.clone(false);
cloneTemplate.setMatteBackground();
- const doc: Doc = cloneTemplate.getRenderedDoc()!;
- this._variationURLs = await this._props.menu.generateVariations(doc, this.prompt, this.fireflyOptions);
- this._variationURLs.forEach(() => {
- const newTemplate: Template = this._props.template.clone(true);
- this._props.menu._variations.push(newTemplate);
- });
- setTimeout(() => {
- this._variationURLs.forEach((url, i) => {
- this._props.menu._variations[i].setImageAsBackground(url, true);
- });
- this._loading = false;
- });
- }
-
- setPromptInputRef: React.LegacyRef<HTMLTextAreaElement> = (node) => {
- this.promptInput = node;
- }
-
- // eslint-disable-next-line
- private optionsButtonOpts: [IconProp, () => any] = ['gear', () => {}];
- // eslint-disable-next-line
- private previewBoxRightButtonOpts: [IconProp, () => any] = ['gear', () => this.forceUpdate()];
+ const doc = cloneTemplate.getRenderedDoc()!;
+ this._props.menu.generateVariations(doc, this._prompt, this._fireflyOptions).then(
+ action((urls: string[]) => {
+ (this._variationURLs = urls).forEach(url => {
+ const template = this._props.template.clone(true);
+ template.setImageAsBackground(url, true);
+ this._props.menu._variations.push(template);
+ });
+ this._loading = false;
+ })
+ );
+ });
render() {
return (
- <div className='docCreatorMenu-editing-firefly-section'>
- <div className="docCreatorMenu-option-divider full no-margin-bottom"/>
+ <div className="docCreatorMenu-editing-firefly-section">
+ <div className="docCreatorMenu-option-divider full no-margin-bottom" />
<TemplatePreviewGrid
menu={this._props.menu}
- title={'Generate Variations'}
+ title="Generate Variations"
loading={this._loading}
- styles={'scrolling'}
+ styles="scrolling"
templates={this._props.menu._variations}
- optionsButtonOpts={this.optionsButtonOpts}
- previewBoxRightButtonOpts={this.previewBoxRightButtonOpts}
+ optionsButtonOpts={this._optionsButtonOpts}
+ previewBoxRightButtonOpts={this._previewBoxRightButtonOpts}
/>
<div className="docCreatorMenu-firefly-options">
<div className="docCreatorMenu-variation-prompt-row">
<textarea
className="docCreatorMenu-variation-prompt-input-textbox"
- ref={this.setPromptInputRef}
- onChange={e => { this.prompt = e.target.value }}
+ ref={action((node: HTMLTextAreaElement | null) => (this._promptInput = node))}
+ onChange={e => (this._prompt = e.target.value)}
onInput={() => {
- if (this.promptInput !== null) {
- this.promptInput.style.height = 'auto';
- this.promptInput.style.height = this.promptInput.scrollHeight + 'px';
+ if (this._promptInput !== null) {
+ this._promptInput.style.height = 'auto';
+ this._promptInput.style.height = this._promptInput.scrollHeight + 'px';
}
}}
- defaultValue={''}
- placeholder={'Enter a custom prompt here (optional)'}
+ defaultValue=""
+ placeholder="Enter a custom prompt here (optional)"
/>
- <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations}/>
+ <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations} />
</div>
- <nav className="options‑menu">
- <label 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>
- </label>
- <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>
+ <nav className="options‑menu">
+ <label className="menu‑item switch">
+ <input type="checkbox" checked={this._fireflyOptions.useStyleRef} onChange={action(e => (this._fireflyOptions.useStyleRef = e.target.checked))} />
+ <span className="slider round"></span>
+ <span className="firefly-option-label">Use template as style guide</span>
+ </label>
+ <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={action(e => (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={action(e => (this._fireflyOptions.temperature = Number(e.target.value)))} />
+ <span className="value" id="tempVal">
+ {this._fireflyOptions.temperature}
+ </span>
+ </div>
+ </nav>
</div>
</div>
- )
+ );
}
}
@@ -144,11 +125,9 @@ interface TemplateEditingWindowProps {
@observer
export class TemplateEditingWindow extends ObservableReactComponent<TemplateEditingWindowProps> {
-
private disposers: { [name: string]: IDisposer } = {};
- @observable private previewWindow: HTMLDivElement | null = null;
-
+ @observable private _previewWindow: HTMLDivElement | null = null;
@observable _variationsTabOpen: boolean = false;
constructor(props: TemplateEditingWindowProps) {
@@ -157,83 +136,85 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
}
componentDidMount(): void {
- this.disposers.windowDimensions = reaction(() =>
- this._props.menu._resizing,
- () => { this.forceUpdate() },
+ 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);
+ if (this._previewWindow && open) {
+ this._previewWindow.style.height = String(Number(this._previewWindow.clientHeight) * 0.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;
+ };
+ previewPanelWidth = () => this._previewWindow?.clientWidth ?? 500;
+ previewPanelHeight = () => this._previewWindow?.clientHeight ?? 500;
+ previewScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+ get renderedDocPreview() {
+ const doc = this._props.template.getRenderedDoc();
return (
- <div className="docCreatorMenu-expanded-template-preview" ref={this.setContainerRef}>
- {this.previewWindow ? <DocumentView
- Document={doc}
- isContentActive={emptyFunction}
- addDocument={returnFalse}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- PanelWidth={() => this.previewWindow?.clientWidth ?? 500}
- PanelHeight={() => this.previewWindow?.clientHeight ?? 500}
- ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
- renderDepth={5}
- whenChildContentsActiveChanged={emptyFunction}
- focus={emptyFunction}
- styleProvider={DefaultStyleProvider}
- addDocTab={DocumentViewInternal.addDocTabFunc}
- pinToPres={() => undefined}
- childFilters={returnEmptyFilter}
- childFiltersByRanges={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- fitContentsToBox={returnFalse}
- fitWidth={returnFalse}
- /> : null}
+ <div className="docCreatorMenu-expanded-template-preview" ref={action((node: HTMLDivElement | null) => (this._previewWindow = node))}>
+ {this._previewWindow && doc ? (
+ <DocumentView
+ Document={doc}
+ isContentActive={emptyFunction}
+ addDocument={returnFalse}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ PanelWidth={this.previewPanelWidth}
+ PanelHeight={this.previewPanelHeight}
+ ScreenToLocalTransform={this.previewScreenToLocalXf}
+ renderDepth={5}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={emptyFunction}
+ styleProvider={DefaultStyleProvider}
+ addDocTab={DocumentViewInternal.addDocTabFunc}
+ pinToPres={emptyFunction}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ // fitContentsToBox={returnFalse}
+ // fitWidth={returnFalse}
+ />
+ ) : null}
</div>
- )
+ );
}
+ expandFunc = () => {
+ // if (this._props.template === this._props.menu._selectedTemplate) {
+ // this._props.menu.updateRenderedPreviewCollection(this._props.template);
+ // }
+ this._props.menu.setExpandedView(undefined);
+ };
+ lastFunc = () => {
+ this._props.menu.editLastTemplate();
+ this.forceUpdate();
+ };
+ variationFunc = () => this.setVariationTab(!this._variationsTabOpen);
render() {
return (
- <div className='docCreatorMenu-templates-view'>
+ <div className="docCreatorMenu-templates-view">
<div className="docCreatorMenu-expanded-template-preview">
- <div className="top-panel"/>
+ <div className="top-panel" />
{this.renderedDocPreview}
- {this._variationsTabOpen ? <FireflyVariationsTab
- menu={this._props.menu}
- template={this._props.template}
- />
- : 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) {
- // this._props.menu.updateRenderedPreviewCollection(this._props.template);
- // }
- this._props.menu.setExpandedView(undefined);
- }}/>
- <DocCreatorMenuButton icon={'lightbulb'} function={() => this.setVariationTab(!this._variationsTabOpen)}/>
- <DocCreatorMenuButton icon={'arrow-rotate-backward'} function={() => { this._props.menu.editLastTemplate(); this.forceUpdate(); }}/>
+ <DocCreatorMenuButton icon="minimize" function={this.expandFunc} />
+ <DocCreatorMenuButton icon="lightbulb" function={this.variationFunc} />
+ <DocCreatorMenuButton icon="arrow-rotate-backward" function={this.lastFunc} />
</div>
</div>
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
index a4da54392..f0e20837c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
@@ -1,11 +1,11 @@
-import { makeObservable, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { Col, DocCreatorMenu } from "../DocCreatorMenu";
-import React from "react";
-import { Conditional, TemplateManager } from "../Backend/TemplateManager";
-import { TemplateFieldType, TemplateFieldSize } from "../TemplateBackend";
-import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
+import { action, makeObservable, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { Col, DocCreatorMenu } from '../DocCreatorMenu';
+import React from 'react';
+import { Conditional, TemplateManager } from '../Backend/TemplateManager';
+import { TemplateFieldType, TemplateFieldSize } from '../TemplateBackend';
+import { DocCreatorMenuButton } from './DocCreatorMenuButton';
interface TemplateMenuFieldOptionsProps {
menu: DocCreatorMenu;
@@ -14,7 +14,6 @@ interface TemplateMenuFieldOptionsProps {
@observer
export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateMenuFieldOptionsProps> {
-
@observable _collapsedCols: string[] = []; //any columns whose options panels are hidden
constructor(props: TemplateMenuFieldOptionsProps) {
@@ -34,160 +33,153 @@ export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateM
condition: '',
target: 'Own',
attribute: '',
- value: ''
+ value: '',
});
}
return this._newCondCache[title];
};
conditionForm = (title: string, parameters?: Conditional, empty: boolean = false) => {
-
- const contentFieldTitles = this._props.menu.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA).map(field => field.title).concat('Template');
+ const contentFieldTitles = this._props.menu.fieldsInfos
+ .filter(field => field.type !== TemplateFieldType.DATA)
+ .map(field => field.title)
+ .concat('Template');
const params: Conditional = this.getParams(title, parameters);
return (
- <div className='form'>
- <div className='form-row'>
- <div className='form-row-plain-text'>If</div>
- <div className='form-row-plain-text'>{title}</div>
- <div className="operator-options-dropdown">
- <span className="operator-dropdown-current">{params.operator ?? '='}</span>
- <div className='operator-dropdown-option' onPointerDown={() => {params.operator = '='}}>{'='}</div>
- </div>
- <input
- className="form-row-textarea"
- onChange={e => runInAction(() => { params.condition = e.target.value })}
- placeholder='value'
- value={params.condition}
- />
- <div className='form-row-plain-text'>then</div>
- <div className="operator-options-dropdown">
- <span className="operator-dropdown-current">{params.target ?? 'Own'}</span>
- {contentFieldTitles.map((fieldTitle, i) =>
- <div className='operator-dropdown-option' key={i} onPointerDown={() => {params.target = fieldTitle}}>{fieldTitle === title ? 'Own' : fieldTitle}</div>
- )}
+ <div className="form">
+ <div className="form-row">
+ <div className="form-row-plain-text">If</div>
+ <div className="form-row-plain-text">{title}</div>
+ <div className="operator-options-dropdown">
+ <span className="operator-dropdown-current">{params.operator ?? '='}</span>
+ <div className="operator-dropdown-option" onPointerDown={() => (params.operator = '=')}>
+ {'='}
+ </div>
+ </div>
+ <input className="form-row-textarea" onChange={action(e => (params.condition = e.target.value))} placeholder="value" value={params.condition} />
+ <div className="form-row-plain-text">then</div>
+ <div className="operator-options-dropdown">
+ <span className="operator-dropdown-current">{params.target ?? 'Own'}</span>
+ {contentFieldTitles.map((fieldTitle, i) => (
+ <div className="operator-dropdown-option" key={i} onPointerDown={() => (params.target = fieldTitle)}>
+ {fieldTitle === title ? 'Own' : fieldTitle}
+ </div>
+ ))}
+ </div>
+ <input className="form-row-textarea" onChange={action(e => (params.attribute = e.target.value))} placeholder="attribute" value={params.attribute} />
+ <div className="form-row-plain-text">{'becomes'}</div>
+ <input className="form-row-textarea" onChange={action(e => (params.value = e.target.value))} placeholder="value" value={params.value} />
</div>
- <input
- className="form-row-textarea"
- onChange={e => runInAction(() => { params.attribute = e.target.value })}
- placeholder='attribute'
- value={params.attribute}
- />
- <div className='form-row-plain-text'>{'becomes'}</div>
- <input
- className="form-row-textarea"
- onChange={e => runInAction(() => { params.value = e.target.value })}
- placeholder='value'
- value={params.value}
- />
+ {empty ? (
+ <DocCreatorMenuButton
+ icon={'plus'}
+ styles={'float-right border'}
+ function={() => {
+ this._newCondCache[title] = observable<Conditional>({
+ field: title,
+ operator: '=',
+ condition: '',
+ target: 'Own',
+ attribute: '',
+ value: '',
+ });
+ this._props.templateManager.addFieldCondition(title, params);
+ }}
+ />
+ ) : (
+ <DocCreatorMenuButton icon={'minus'} styles={'float-right border'} function={() => this._props.templateManager.removeFieldCondition(title, params)} />
+ )}
</div>
- {empty ?
- <DocCreatorMenuButton icon={'plus'} styles={'float-right border'} function={() => {
- this._newCondCache[title] = observable<Conditional>({
- field: title,
- operator: '=',
- condition: '',
- target: 'Own',
- attribute: '',
- value: ''
- });
- this._props.templateManager.addFieldCondition(title, params);
- }}/>
- :
- <DocCreatorMenuButton icon={'minus'} styles={'float-right border'} function={() => this._props.templateManager.removeFieldCondition(title, params)}/>
- }
- </div>
- )
- }
+ );
+ };
fieldPanel = (field: Col, id: number) => (
<div className="field-panel" key={id}>
- <div className="top-bar" onPointerDown={e => this._props.menu.setUpButtonClick(e, runInAction(() => () => {
- if (this._collapsedCols.includes(field.title)) {
- this._collapsedCols = this._collapsedCols.filter(col => col !== field.title);
- } else {
- this._collapsedCols.push(field.title);
- }
- }))}>
+ <div
+ className="top-bar"
+ onPointerDown={e =>
+ this._props.menu.setUpButtonClick(
+ e,
+ action(() => {
+ if (this._collapsedCols.includes(field.title)) {
+ this._collapsedCols = this._collapsedCols.filter(col => col !== field.title);
+ } else {
+ this._collapsedCols.push(field.title);
+ }
+ })
+ )
+ }>
<span className="field-title">{`${field.title} Field`}</span>
- <DocCreatorMenuButton icon={'minus'} styles={'no-margin absolute-right'} function={() => this._props.menu.removeField(field)}/>
+ <DocCreatorMenuButton icon={'minus'} styles={'no-margin absolute-right'} function={() => this._props.menu.removeField(field)} />
</div>
- { this._collapsedCols.includes(field.title) ? null :
+ {this._collapsedCols.includes(field.title) ? null : (
<>
- <div className="opts-bar">
- <div className="opt-box">
- <div className="top-bar"> Title </div>
- <textarea className="content" style={{ width: '100%', height: 'calc(100% - 20px)' }} value={field.title} placeholder={'Enter title'} onChange={e => this._props.menu.setColTitle(field, e.target.value)} />
- </div>
- <div className="opt-box">
- <div className="top-bar"> Type </div>
- <div className="content">
- <span className="type-display">{
- field.type === TemplateFieldType.TEXT ? 'Text Field'
- : field.type === TemplateFieldType.VISUAL ? 'File Field'
- : field.type === TemplateFieldType.DATA ? 'Data Field'
- : ''
- }</span>
- <div className="bubbles">
- <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.TEXT)} />
- <div className="text">Text</div>
- <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.VISUAL)} />
- <div className="text">File</div>
- <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.DATA)} />
- <div className="text">Data</div>
- </div>
+ <div className="opts-bar">
+ <div className="opt-box">
+ <div className="top-bar"> Title </div>
+ <textarea className="content" style={{ width: '100%', height: 'calc(100% - 20px)' }} value={field.title} placeholder={'Enter title'} onChange={e => this._props.menu.setColTitle(field, e.target.value)} />
</div>
- </div>
- </div>
- { field.type === TemplateFieldType.DATA ? null :
- (<>
- <div className="sizes-box">
- <div className="top-bar"> Valid Sizes </div>
+ <div className="opt-box">
+ <div className="top-bar"> Type </div>
<div className="content">
+ <span className="type-display">{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : field.type === TemplateFieldType.DATA ? 'Data Field' : ''}</span>
<div className="bubbles">
- {Object.values(TemplateFieldSize).map(size => (
- <div key={field + size}>
- <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this._props.menu.modifyColSizes(field, size, e.target.checked)} />
- <div className="text">{size}</div>
- </div>
- ))}
+ <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.TEXT)} />
+ <div className="text">Text</div>
+ <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.VISUAL)} />
+ <div className="text">File</div>
+ <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.DATA)} />
+ <div className="text">Data</div>
</div>
</div>
</div>
- <div className="desc-box">
- <div className="top-bar"> Prompt </div>
- <textarea
- className="content"
- onChange={e => this._props.menu.setColDesc(field, e.target.value)}
- defaultValue={field.desc === this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc}
- placeholder={this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'}
- />
- </div>
- </>)
- }
- <div className="conditionals-section">
- <span className="conditionals-title">Conditional Logic</span>
- {this.conditionForm(field.title, undefined, true)}
- {this._props.templateManager.conditionalFieldLogic[field.title]?.map(condition => this.conditionForm(condition.field, condition))}
- </div>
+ </div>
+ {field.type === TemplateFieldType.DATA ? null : (
+ <>
+ <div className="sizes-box">
+ <div className="top-bar"> Valid Sizes </div>
+ <div className="content">
+ <div className="bubbles">
+ {Object.values(TemplateFieldSize).map(size => (
+ <div key={field + size}>
+ <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this._props.menu.modifyColSizes(field, size, e.target.checked)} />
+ <div className="text">{size}</div>
+ </div>
+ ))}
+ </div>
+ </div>
+ </div>
+ <div className="desc-box">
+ <div className="top-bar"> Prompt </div>
+ <textarea
+ className="content"
+ onChange={e => this._props.menu.setColDesc(field, e.target.value)}
+ defaultValue={field.desc === this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc}
+ placeholder={this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'}
+ />
+ </div>
+ </>
+ )}
+ <div className="conditionals-section">
+ <span className="conditionals-title">Conditional Logic</span>
+ {this.conditionForm(field.title, undefined, true)}
+ {this._props.templateManager._conditionalFieldLogic[field.title]?.map(condition => this.conditionForm(condition.field, condition))}
+ </div>
</>
- }
+ )}
</div>
);
-
-
render() {
return (
<div className="docCreatorMenu-dashboard-view">
<div className="topbar">
- <DocCreatorMenuButton icon={'plus'} function={this._props.menu.addField}/>
- <DocCreatorMenuButton icon={'arrow-left'} styles={'float-right'} function={() => runInAction(() => (this._props.menu._menuContent = 'templates'))}/>
+ <DocCreatorMenuButton icon="plus" function={this._props.menu.addField} />
+ <DocCreatorMenuButton icon="arrow-left" styles="float-right" function={action(() => (this._props.menu._menuContent = 'templates'))} />
</div>
<div className="panels-container">{this._props.menu.fieldsInfos.map((field, i) => this.fieldPanel(field, i))}</div>
</div>
);
}
-
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
index dc4c35789..7d02fff12 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
@@ -1,35 +1,30 @@
-import { Colors } from "@dash/components/src";
-import { FontAwesomeIcon} from "@fortawesome/react-fontawesome";
-import { Template } from "../Template";
-import { makeObservable, observable } from "mobx";
-import React from "react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { DocCreatorMenu } from "../DocCreatorMenu";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { DocumentView } from "../../../DocumentView";
-import { emptyFunction } from "../../../../../../Utils";
-import { returnEmptyFilter, returnFalse } from "../../../../../../ClientUtils";
-import { Transform } from "../../../../../util/Transform";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { observer } from "mobx-react";
+import { Colors } from '@dash/components/src';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Template } from '../Template';
+import { action, makeObservable, observable } from 'mobx';
+import React from 'react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { DocCreatorMenu } from '../DocCreatorMenu';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { DocumentView } from '../../../DocumentView';
+import { emptyFunction } from '../../../../../../Utils';
+import { returnEmptyFilter, returnFalse } from '../../../../../../ClientUtils';
+import { Transform } from '../../../../../util/Transform';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { Doc, returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { observer } from 'mobx-react';
export interface TemplatePreviewBoxProps {
template: Template;
menu: DocCreatorMenu; // eslint-disable-next-line
- leftButtonOpts?: [icon: IconProp, func: (...args: any) => void] // eslint-disable-next-line
- rightButtonOpts?: [icon: IconProp, func: (...args: any) => void]
+ leftButtonOpts?: [icon: IconProp, func: (...args: any) => void]; // eslint-disable-next-line
+ rightButtonOpts?: [icon: IconProp, func: (...args: any) => void];
}
@observer
export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreviewBoxProps> {
-
@observable private previewWindow: HTMLDivElement | null = null;
- setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
- this.previewWindow = node;
- }
-
constructor(props: TemplatePreviewBoxProps) {
super(props);
makeObservable(this);
@@ -39,6 +34,10 @@ export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreview
return this._props.template.getRenderedDoc() as Doc;
}
+ docPanelWidth = () => this.previewWindow?.clientWidth ?? this._props.menu._menuDimensions.height * 0.3;
+ docPanelHeight = () => this.previewWindow?.clientHeight ?? this._props.menu._menuDimensions.height * 0.3;
+ docScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+
render() {
const template = this._props.template;
@@ -46,49 +45,45 @@ export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreview
<div
key={template.title}
className="docCreatorMenu-preview-window"
- ref={this.setContainerRef}
+ ref={action((node: HTMLDivElement | null) => (this.previewWindow = node))}
style={{
border: this._props.menu._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
boxShadow: this._props.menu._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '',
}}
- onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.menu.updateSelectedTemplate(template))}
- >
- { this._props.leftButtonOpts ?
- <button
- className="option-button left"
- onPointerDown={e =>
- this._props.menu.setUpButtonClick(e, () => this._props.leftButtonOpts![1](template))
- }>
+ onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.menu.updateSelectedTemplate(template))}>
+ {this._props.leftButtonOpts ? (
+ <button className="option-button left" onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.leftButtonOpts![1](template))}>
<FontAwesomeIcon icon={this._props.leftButtonOpts![0]} color="white" />
- </button> : null
- }
- { this._props.rightButtonOpts ?
+ </button>
+ ) : null}
+ {this._props.rightButtonOpts ? (
<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 }
- <DocumentView
- Document={this.doc}
- isContentActive={emptyFunction} // !!! should be return false
- addDocument={returnFalse}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- PanelWidth={() => this.previewWindow?.clientWidth ?? this._props.menu._menuDimensions.height * .3}
- PanelHeight={() => this.previewWindow?.clientHeight ?? this._props.menu._menuDimensions.height * .3}
- ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
- renderDepth={1}
- whenChildContentsActiveChanged={emptyFunction}
- focus={emptyFunction}
- styleProvider={DefaultStyleProvider}
- addDocTab={this._props.menu._props.addDocTab}
- pinToPres={() => undefined}
- childFilters={returnEmptyFilter}
- childFiltersByRanges={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- fitContentsToBox={returnFalse}
- fitWidth={returnFalse}
- hideDecorations={true}
- />
+ </button>
+ ) : null}
+ <DocumentView
+ Document={this.doc}
+ isContentActive={emptyFunction} // !!! should be return false
+ addDocument={returnFalse}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ PanelWidth={this.docPanelWidth}
+ PanelHeight={this.docPanelHeight}
+ ScreenToLocalTransform={this.docScreenToLocalXf}
+ renderDepth={1}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={emptyFunction}
+ styleProvider={DefaultStyleProvider}
+ addDocTab={this._props.menu._props.addDocTab}
+ pinToPres={emptyFunction}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ // fitContentsToBox={returnFalse}
+ // fitWidth={returnFalse}
+ hideDecorations={true}
+ />
</div>
- )
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
index f281f770e..9222d7349 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
@@ -1,20 +1,20 @@
-import { action, computed, makeObservable, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { DocCreatorMenu, LayoutType } from "../DocCreatorMenu";
-import React from "react";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
-import { emptyFunction } from "../../../../../../Utils";
-import { undoable } from "../../../../../util/UndoManager";
-import ReactLoading from "react-loading";
-import { Doc, NumListCast, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { StrCast } from "../../../../../../fields/Types";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { DocumentView } from "../../../DocumentView";
-import { Transform } from "../../../../../util/Transform";
-import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { DocCreatorMenu, LayoutType } from '../DocCreatorMenu';
+import React from 'react';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from '../../../../../../ClientUtils';
+import { emptyFunction } from '../../../../../../Utils';
+import { undoable } from '../../../../../util/UndoManager';
+import ReactLoading from 'react-loading';
+import { Doc, NumListCast, returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { NumCast, StrCast } from '../../../../../../fields/Types';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { DocumentView } from '../../../DocumentView';
+import { Transform } from '../../../../../util/Transform';
+import { Docs, DocumentOptions } from '../../../../../documents/Documents';
interface TemplatesRenderPreviewWindowProps {
menu: DocCreatorMenu;
@@ -22,8 +22,7 @@ interface TemplatesRenderPreviewWindowProps {
@observer
export class TemplatesRenderPreviewWindow extends ObservableReactComponent<TemplatesRenderPreviewWindowProps> {
-
- @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 0, repeat: 0 };
+ @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 1, repeat: 0 };
@observable private renderedDocs: Doc[] = [];
@observable private renderedDocCollection: Doc | undefined = undefined;
@@ -62,7 +61,7 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
@computed get columnsCount() {
switch (this._layout.type) {
case LayoutType.FREEFORM:
- return this._layout.columns ?? 0;
+ return this._layout.columns ?? 1;
case LayoutType.CAROUSEL3D:
return 3;
default:
@@ -130,28 +129,27 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
const { horizontalSpan, verticalSpan } = this.previewInfo;
collection._height = verticalSpan;
collection._width = horizontalSpan;
-
- const columns: number = this._layout.columns ?? this.columnsCount;
- const xGap: number = this._layout.xMargin;
- const yGap: number = this._layout.yMargin;
- const startX: number = -Number(collection._width) / 2;
- const startY: number = -Number(collection._height) / 2;
- const docHeight: number = Number(docs[0]._height);
- const docWidth: number = Number(docs[0]._width);
-
- if (columns === 0 || docs.length === 0) {
- return;
- }
-
- let i: number = 0;
- let docsChanged: number = 0;
- let curX: number = startX;
- let curY: number = startY;
+ collection.layout_fitWidth = true;
+ collection.freeform_fitContentsToBox = true;
+
+ const columns = (this._layout.columns ?? this.columnsCount) || 1;
+ const xGap = this._layout.xMargin;
+ const yGap = this._layout.yMargin;
+ const startX = -collection._width / 2;
+ const startY = -collection._height / 2;
+ const docHeight = NumCast(docs[0]?._height);
+ const docWidth = NumCast(docs[0]?._width);
+
+ let i = 0;
+ let docsChanged = 0;
+ let curX = startX;
+ let curY = startY;
while (docsChanged < docs.length) {
while (i < columns && docsChanged < docs.length) {
docs[docsChanged].x = curX;
docs[docsChanged].y = curY;
+ docs[docsChanged].layout_fitWidth = false;
curX += docWidth + xGap;
++docsChanged;
++i;
@@ -164,8 +162,8 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
@computed
get previewInfo() {
- const docHeight: number = Number(this.renderedDocs[0]._height);
- const docWidth: number = Number(this.renderedDocs[0]._width);
+ const docHeight = NumCast(this.renderedDocs[0]?._height);
+ const docWidth = NumCast(this.renderedDocs[0]?._width);
const layout = this._layout;
return {
docHeight: docHeight,
@@ -201,6 +199,10 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
}
}
+ layoutPanelWidth = () => this._props.menu._menuDimensions.width - 80;
+ layoutPanelHeight = () => this._props.menu._menuDimensions.height - 105;
+ layoutScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+
layoutPreviewContents = action(() => {
return this.loading ? (
<div className="docCreatorMenu-layout-preview-window-wrapper loading">
@@ -216,20 +218,18 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
addDocument={returnFalse}
moveDocument={returnFalse}
removeDocument={returnFalse}
- PanelWidth={() => this._props.menu._menuDimensions.width - 80}
- PanelHeight={() => this._props.menu._menuDimensions.height - 105}
- ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
+ PanelWidth={this.layoutPanelWidth}
+ PanelHeight={this.layoutPanelHeight}
+ ScreenToLocalTransform={this.layoutScreenToLocalXf}
renderDepth={5}
whenChildContentsActiveChanged={emptyFunction}
focus={emptyFunction}
styleProvider={DefaultStyleProvider}
addDocTab={this._props.menu._props.addDocTab}
- pinToPres={() => undefined}
+ pinToPres={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
- fitContentsToBox={returnFalse}
- fitWidth={returnFalse}
hideDecorations={true}
/>
</div>
@@ -273,7 +273,6 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
};
get optionsMenuContents() {
-
const repeatOptions = [0, 1, 2, 3, 4, 5];
return (
@@ -341,5 +340,7 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
);
}
- render() { return this.optionsMenuContents }
-} \ No newline at end of file
+ render() {
+ return this.optionsMenuContents;
+ }
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index 7591740e0..e2a2a3c1c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -9,7 +9,7 @@ import { TemplateDataField } from './TemplateFieldTypes/DataField';
export class Template {
_mainField: DynamicField;
- private dataFields: TemplateDataField[] = [];
+ private _dataFields: TemplateDataField[] = [];
/**
* A Template can be created from a description of its fields (FieldSettings) or from a DynamicField
@@ -20,37 +20,13 @@ export class Template {
this._mainField = definition instanceof DynamicField ? definition : this.setupMainField(definition);
}
- get childFields(): TemplateField[] {
- return this._mainField?.getSubfields ?? [];
- }
- get allFields(): TemplateField[] {
- return this._mainField?.getAllSubfields ?? [];
- }
- get contentFields(): TemplateField[] {
- return this.allFields.filter(field => field.isContentField);
- }
- get doc() {
- return this._mainField?.renderedDoc;
- }
- get title() {
- return this._mainField?.getTitle();
- }
-
- get descriptionSummary(): string {
- let summary: string = '';
- this.contentFields.forEach(field => {
- summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`;
- });
- return summary;
- }
-
- get compiledContent(): string {
- let summary: string = '';
- this.contentFields.forEach(field => {
- summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
- });
- return summary;
- }
+ get childFields() { return this._mainField?.getSubfields ?? []; } // prettier-ignore
+ get allFields() { return this._mainField?.getAllSubfields ?? []; } // prettier-ignore
+ get contentFields() { return this.allFields.filter(field => field.isContentField); } // prettier-ignore
+ get doc() { return this._mainField?.renderedDoc; } // prettier-ignore
+ get title() { return this._mainField?.getTitle(); } // prettier-ignore
+ get descriptionSummary() { return this.contentFields.map(f => `--- Field #${f.getID} (title: ${f.getTitle()}): ${f.getDescription ?? ''} ---`).join(); } // prettier-ignore
+ get compiledContent() { return this.contentFields.map(f => `--- Field #${f.getID} (title: ${f.getTitle()}): ${f.getContent() ?? ''} ---`).join(); } // prettier-ignore
cleanup = () => {
//dispose each subfields disposers, etc.
@@ -58,61 +34,56 @@ export class Template {
clone = (withContent: boolean = false) => {
const clone = new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings);
- this.dataFields.forEach(field => clone.addDataField(field.title));
+ this._dataFields.forEach(field => clone.addDataField(field.title));
return clone;
};
getRenderedDoc = () => this.doc;
- getFieldByID = (id: number): TemplateField => this.allFields.filter(field => field.getID === id)[0];
+ getFieldByID = (id: number): TemplateField | undefined => this.allFields.filter(field => field.getID === id)[0];
- getFieldByTitle = (title: string) => [...this.allFields, ...this.dataFields].filter(field => field.getTitle() === title)[0];
+ getFieldByTitle = (title: string) => [...this.allFields, ...this._dataFields].filter(field => field.getTitle() === title)[0];
setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField;
assignColToField = (fieldID: number, col: Col) => {
const field = this.getFieldByID(fieldID);
- field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
- field.setTitle(col.title);
- }
+ field?.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+ field?.setTitle(col.title);
+ };
- addDataField = (title: string, content?: string) => {
- this.dataFields.push(new TemplateDataField(title, content));
- }
+ addDataField = (title: string, content?: string) => this._dataFields.push(new TemplateDataField(title, content));
- removeDataField = (title: string) => {
- this.dataFields = this.dataFields.filter(field => !(field.title === title));
- }
+ removeDataField = (title: string) => (this._dataFields = this._dataFields.filter(field => field.title !== title));
- isValidTemplate = (cols: Col[]) => {
- const maxMatches = this.maxMatches(this.getMatches(cols));
- return maxMatches === this.contentFields.length && this.title !== 'template_framework';
- };
+ isValidTemplate = (cols: Col[]) => this.title !== 'template_framework' && this.maxMatches(this.getMatches(cols)) === this.contentFields.length;
applyConditionalLogicToField = (field: TemplateField | TemplateDataField, logic: Record<string, Conditional[]>) => {
if (field instanceof DynamicField) return;
- const fieldStatements: Conditional[] = logic[field.getTitle()];
- const content = field.getContent()
- fieldStatements && fieldStatements.forEach(statement => {
+ const fieldStatements = logic[field.getTitle()];
+ const content = field.getContent();
+ fieldStatements?.forEach(statement => {
if (content === statement.condition) {
if (statement.target === 'Template') {
- this._mainField.renderedDoc![statement.attribute] = statement.value;
- Object.assign(this._mainField.settings.opts, {[statement.attribute]: statement.value});
+ if (this._mainField.renderedDoc) {
+ this._mainField.renderedDoc[statement.attribute] = statement.value;
+ Object.assign(this._mainField.settings.opts, { [statement.attribute]: statement.value });
+ }
} else {
- const targetField: TemplateField = this.getFieldByTitle(statement.target) as TemplateField;
- if (targetField) {
- targetField.renderedDoc![statement.attribute] = statement.value;
- Object.assign(targetField.settings.opts, {[statement.attribute]: statement.value});
- }
+ const targetField = this.getFieldByTitle(statement.target);
+ if (targetField instanceof TemplateField && targetField.renderedDoc) {
+ targetField.renderedDoc[statement.attribute] = statement.value;
+ Object.assign(targetField.settings.opts, { [statement.attribute]: statement.value });
+ }
}
}
- })
- }
+ });
+ };
applyConditionalLogic = (logic: Record<string, Conditional[]>) => {
- const fields: (TemplateField | TemplateDataField)[] = [...this.allFields, ...this.dataFields];
- fields.forEach(field => this.applyConditionalLogicToField(field, logic));
- }
+ [...this.allFields, ...this._dataFields].forEach(field => this.applyConditionalLogicToField(field, logic));
+ return this.getRenderedDoc();
+ };
setImageAsBackground(url: string, makeTransparent: boolean = false) {
const fieldSettings: FieldSettings = {
@@ -120,15 +91,15 @@ export class Template {
br: [1, 1],
opts: {},
viewType: ViewType.IMG,
- }
+ };
- const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+ const field = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
field.setContent(url);
if (makeTransparent) {
- this.allFields.forEach(field => {
- field.updateDocSetting('backgroundColor', 'transparent');
- field.updateDocSetting('borderWidth', '0');
+ this.allFields.forEach(aField => {
+ aField.updateDocSetting('backgroundColor', 'transparent');
+ aField.updateDocSetting('borderWidth', '0');
});
}
@@ -138,7 +109,7 @@ export class Template {
/**
* This function is just a hack for now to get around weird document icon stuff (specifically it misses the background)
*/
- setMatteBackground(makeTransparent: boolean = false) {
+ setMatteBackground(makeTransparent: boolean = false) {
if (this._mainField.hasBackground) {
return;
}
@@ -146,18 +117,17 @@ export class Template {
const fieldSettings: FieldSettings = {
tl: [-1, -1],
br: [1, 1],
- opts: {backgroundColor: String(this._mainField.renderedDoc!.backgroundColor)},
+ opts: { backgroundColor: String(this._mainField.renderedDoc!.backgroundColor) },
viewType: ViewType.TEXT,
- }
+ };
- const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+ const field = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
- if (makeTransparent) {
- this.allFields.forEach(field => {
- field.updateDocSetting('backgroundColor', 'transparent');
- field.updateDocSetting('borderWidth', '0');
+ makeTransparent &&
+ this.allFields.forEach(aField => {
+ aField.updateDocSetting('backgroundColor', 'transparent');
+ aField.updateDocSetting('borderWidth', '0');
});
- }
this._mainField.makeBackgroundField(field);
}
@@ -167,9 +137,7 @@ export class Template {
if (cols.length !== numFields) return [];
- const matches: number[][] = Array(numFields)
- .fill([])
- .map(() => []);
+ const matches = Array<number[]>(numFields);
this.contentFields.forEach((field, i) => (matches[i] = field.matches(cols)));
@@ -180,8 +148,8 @@ export class Template {
if (matches.length === 0) return 0;
const fieldsCt = this.contentFields.length;
- const used: boolean[] = Array(fieldsCt).fill(false);
- const mt: number[] = Array(fieldsCt).fill(-1);
+ const used = Array<boolean>(fieldsCt).fill(false);
+ const mt = Array<number>(fieldsCt).fill(-1);
const augmentingPath = (v: number): boolean => {
if (!used[v]) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
index c100d1cce..091ef834a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -67,13 +67,13 @@ export abstract class TemplateField {
setTitle = (title: string) => {
this._title = title;
this.settings.title = title;
- if (this._renderDoc) this._renderDoc.title = title
+ if (this._renderDoc) this._renderDoc.title = title;
};
getTitle = () => this._title;
updateDocSetting(setting: string, newVal: string) {
if (this._renderDoc) this._renderDoc[setting] = newVal;
- const settings: {[s: string]: string } = {[setting]: newVal}
+ const settings: { [s: string]: string } = { [setting]: newVal };
Object.assign(this.settings.opts, settings);
}
@@ -162,7 +162,7 @@ export enum ViewType {
DEC = 'decoration',
IMG = 'image',
TEXT = 'text',
- NONE = 'none'
+ NONE = 'none',
}
export type FieldDimensions = {
@@ -170,4 +170,3 @@ export type FieldDimensions = {
height: number;
coord: { x: number; y: number };
};
-
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 30fc44f62..8ed59c6e1 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -175,6 +175,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width), height: this.layoutDoc._height }),
({ nativeSize, width, height }) => {
if (!this.layoutDoc._layout_nativeDimEditable || !height || this.layoutDoc.layout_resetNativeDim) {
+ if (!this._props.TemplateDataDocument) this.layoutDoc._nativeWidth = this.layoutDoc._nativeHeight = undefined;
this.layoutDoc.layout_resetNativeDim = undefined; // reset dimensions of templates rendered with content or if image changes. afterwards, remove this flag.
this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
}