aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx')
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx290
1 files changed, 28 insertions, 262 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 02fd7f869..36264f886 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -29,8 +29,10 @@ import './DocCreatorMenu.scss';
import { DefaultStyleProvider, returnEmptyDocViewList } from '../../../StyleProvider';
import { Transform } from '../../../../util/Transform';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
-import { FieldOpts, FieldSettings } from './FieldTypes/StaticField';
+import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
+import { TemplateManager } from './TemplateManager';
+import { Template } from './Template';
+import { Field, FieldContentType } from './FieldTypes/Field';
export enum LayoutType {
STACKED = 'stacked',
@@ -49,6 +51,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
private _ref: HTMLDivElement | null = null;
+ private templateManager: TemplateManager;
+
@observable _fullyRenderedDocs: Doc[] = [];
@observable _renderedDocCollectionPreview: Doc | undefined = undefined;
@observable _renderedDocCollection: Doc | undefined = undefined;
@@ -99,6 +103,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
super(props);
makeObservable(this);
DocCreatorMenu.Instance = this;
+ this.templateManager = new TemplateManager(TemplateLayouts.allTemplates);
//setTimeout(() => this.generateTemplates(''));
}
@@ -562,79 +567,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
}
};
- matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => {
- const colMatchesField = (col: Col, field: FieldSettings) => {
- return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
- };
-
- const matches: number[][] = Array(template.fields.length)
- .fill([])
- .map(() => []);
-
- template.fields.forEach((field, i) => {
- cols.forEach((col, v) => {
- if (colMatchesField(col, field)) {
- matches[i].push(v);
- }
- });
- });
-
- return matches;
- };
-
- maxMatches = (fieldsCt: number, matches: number[][]) => {
- const used: boolean[] = Array(fieldsCt).fill(false);
- const mt: number[] = Array(fieldsCt).fill(-1);
-
- const augmentingPath = (v: number): boolean => {
- if (used[v]) return false;
- used[v] = true;
- for (const to of matches[v]) {
- if (mt[to] === -1 || augmentingPath(mt[to])) {
- mt[to] = v;
- return true;
- }
- }
- return false;
- };
-
- for (let v = 0; v < fieldsCt; ++v) {
- used.fill(false);
- augmentingPath(v);
- }
-
- let count: number = 0;
-
- for (let i = 0; i < fieldsCt; ++i) {
- if (mt[i] !== -1) ++count;
- }
-
- return count;
- };
-
- findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
- let validTemplates: any[] = [];
- templates.forEach(template => {
- const numFields = template.fields.length;
- if (!(numFields === cols.length)) return;
- const matches = this.matchesForTemplate(template, cols);
- if (this.maxMatches(numFields, matches) === numFields) {
- validTemplates.push(template.title);
- }
- });
-
- validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
-
- return validTemplates;
- };
-
/**
* Populates a preset template framework with content from a datavizbox or any AI-generated content.
* @param template the preloaded template framework being filled in
* @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz
* @returns a doc containing the fully rendered template
*/
- fillPresetTemplate = async (template: TemplateDocInfos, assignments: { [field: string]: Col }): Promise<Doc> => {
+ fillPresetTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Doc> => {
const wordLimit = (size: TemplateFieldSize) => {
switch (size) {
case TemplateFieldSize.TINY:
@@ -665,22 +604,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
//console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
Object.entries(assignments).forEach(([title, info]) => {
- const field: FieldSettings = template.fields[Number(info.number)];
+ const field: Field = template.getFieldByID(Number(info.number));
const col = this.getColByTitle(title);
- const doc = FieldUtils.TextField(
- {
- tl: field.tl,
- br: field.br,
- },
- template.height,
- template.width,
- col.title,
- info.content ?? '',
- field.opts
- );
-
- rendered.push(doc);
+ field.setContent(info.content ?? '', FieldContentType.STRING);
+ field.setTitle(col.title);
});
}
} catch (err) {
@@ -691,22 +619,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
return rendered;
};
- const createGeneratedImage = async (fieldNum: string, col: Col, prompt: string) => {
+ const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
const url = await this.generateGPTImage(prompt);
- const field: FieldSettings = template.fields[Number(fieldNum)];
- const doc = FieldUtils.ImageField(
- {
- tl: field.tl,
- br: field.br,
- },
- template.height,
- template.width,
- col.title,
- url ?? '',
- field.opts
- );
+ const field: Field = template.getFieldByID(Number(fieldNum));
- return doc;
+ field.setContent(url ?? '', FieldContentType.IMAGE);
+ field.setTitle(col.title);
};
const renderImageCalls = async (): Promise<Doc[]> => {
@@ -715,7 +633,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
if (calls.length) {
try {
- const renderedImages: Doc[] = await Promise.all(
+ await Promise.all(
calls.map(async ([fieldNum, col]) => {
const sysPrompt =
'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
@@ -724,14 +642,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
col.desc;
const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
- //console.log(sysPrompt, prompt);
- return createGeneratedImage(fieldNum, col, prompt);
+ generateAndLoadImage(fieldNum, col, prompt);
})
);
-
- const renderedTemplates: Doc[] = await Promise.all(renderedImages);
- renderedTemplates.forEach(doc => rendered.push(doc));
} catch (e) {
console.log(e);
}
@@ -740,12 +654,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
return rendered;
};
- const fields: Doc[] = [];
+ const fields: Field[] = [];
- const GPTAssignments = Object.entries(assignments).filter(([f, col]) => this._columns.includes(col));
- const nonGPTAssignments: [string, Col][] = Object.entries(assignments).filter(a => !GPTAssignments.includes(a));
- const GPTTextCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.TEXT);
- const GPTIMGCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
+ const autoLoadedFields = Object.entries(assignments).filter(([f, col]) => this._columns.includes(col));
+ const userCreatedFields: [string, Col][] = Object.entries(assignments).filter(a => !autoLoadedFields.includes(a));
+ const GPTTextCalls = autoLoadedFields.filter(([str, col]) => col.type === TemplateFieldType.TEXT);
+ const GPTIMGCalls = autoLoadedFields.filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
const stringifyGPTInfo = (calls: [string, Col][]): string => {
let string: string = '*** COLUMN INFO:';
@@ -759,9 +673,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
let fieldContent: string = '';
- Object.entries(nonGPTAssignments).forEach(([f, strCol]) => {
- const field: FieldSettings = template.fields[Number(f)];
- const col = strCol[1];
+ Object.entries(userCreatedFields).forEach(([fieldID, strAndCol]) => {
+ const field: Field = template.getFieldByID(Number(fieldID));
+ const col = strAndCol[1];
const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)(
{
@@ -775,7 +689,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
field.opts
);
- fieldContent += `--- Field #${f} (title: ${col.title}): ${col.defaultContent ?? ''} ---`;
+ fieldContent += `--- Field #${fieldID} (title: ${col.title}): ${col.defaultContent ?? ''} ---`;
fields.push(doc);
});
@@ -829,7 +743,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
return createMainDoc();
};
- compileFieldDescriptions = (templates: TemplateDocInfos[]): string => {
+ compileFieldDescriptions = (templates: Template[]): string => {
let descriptions: string = '';
templates.forEach(template => {
descriptions += `---------- NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `;
@@ -898,7 +812,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
this._dataViz?.updateColDefaults();
const cols = this.fieldsInfos;
- const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates);
+ const templates = this.templateManager.getValidTemplates(cols);
const assignments: [TemplateDocInfos, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
@@ -1668,151 +1582,3 @@ export type Col = {
type: TemplateFieldType;
defaultContent?: string;
};
-
-type DecorationField = FieldSettings;
-
-type InkDecoration = {};
-
-type TemplateDecorations = FieldSettings | InkDecoration;
-
-interface TemplateOpts extends FieldOpts {}
-
-export class FieldUtils {
- public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
- const words: string[] = text.split(/\s+/).filter(Boolean);
-
- let currFontSize = 1;
- let rowsCount = 1;
- let currTextHeight = currFontSize * rowsCount * 2;
-
- while (currTextHeight <= contHeight) {
- let wordIndex = 0;
- let currentRowWidth = 0;
- let wordsInCurrRow = 0;
- rowsCount = 1;
-
- while (wordIndex < words.length) {
- const word = words[wordIndex];
- const wordWidth = word.length * currFontSize * 0.5;
- //console.log(wordWidth)
-
- if (currentRowWidth + wordWidth <= contWidth) {
- currentRowWidth += wordWidth;
- ++wordsInCurrRow;
- } else {
- if (words.length !== 1 && words.length > wordsInCurrRow) {
- rowsCount++;
- currentRowWidth = wordWidth;
- wordsInCurrRow = 1;
- } else {
- break;
- }
- }
-
- wordIndex++;
- }
-
- currTextHeight = rowsCount * currFontSize * 2;
- //console.log(rowsCount, currFontSize, currTextHeight)
-
- currFontSize += 1;
- }
-
- return currFontSize - 1;
- };
-
- private static getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
- const l = (coords.tl[0] * parentHeight) / 2;
- const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
- const r = (coords.br[0] * parentHeight) / 2;
- const b = coords.br[1] * parentWidth / 2; //prettier-ignore
- const width = r - l;
- const height = b - t;
- const coord = { x: l, y: t };
- //console.log(coords, parentWidth, parentHeight, height);
- return { width, height, coord };
- };
-
- public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const docWithBasicOpts = Docs.Create.FreeformDocument([], {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- backgroundColor: opts.backgroundColor ?? '',
- _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- hCentering: opts.contentXCentering,
- _rotation: opts.rotation,
- });
-
- return docWithBasicOpts;
- };
-
- public static TextField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const docWithBasicOpts = Docs.Create.TextDocument(content, {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
- backgroundColor: opts.backgroundColor ?? '',
- text_fontColor: opts.color,
- contentBold: opts.fontBold,
- textTransform: opts.fontTransform,
- color: opts.color,
- _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- hCentering: opts.contentXCentering,
- _rotation: opts.rotation,
- });
-
- docWithBasicOpts._layout_hideScroll = true;
-
- return docWithBasicOpts;
- };
-
- public static ImageField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const doc = Docs.Create.ImageDocument(content, {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- _layout_fitWidth: false,
- backgroundColor: opts.backgroundColor ?? '',
- _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- _rotation: opts.rotation,
- });
-
- //setTimeout(() => {doc._height = height; doc._width = width}, 10);
-
- return doc;
- };
-
- public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
-
- return doc;
- };
-}