aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-10-29 04:02:29 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-10-29 04:02:29 -0400
commit691fc130de706c691a42f7e87688c14102016ccc (patch)
treeaf29b634c73be79ee18883ddb1b2d0ef1ab0b80c
parent857797d1d47f22b641d1bddb4177028c26677f19 (diff)
starting to integrate refactor with docreatormenu functionality
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx290
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx15
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx12
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx70
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx37
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx54
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx134
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx23
8 files changed, 215 insertions, 420 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;
- };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 361476446..a55f44589 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -2,7 +2,7 @@ import { Doc } from "../../../../../../fields/Doc";
import { Docs } from "../../../../../documents/Documents";
import { Col } from "../DocCreatorMenu";
import { TemplateLayouts } from "../TemplateBackend";
-import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
import { FieldUtils } from "./FieldUtils";
import { StaticField } from "./StaticField";
@@ -12,6 +12,7 @@ export class DynamicField implements Field {
private id: number;
private settings: FieldSettings;
+ private title: string = '';
private parent: Field;
private dimensions: FieldDimensions;
@@ -30,9 +31,12 @@ export class DynamicField implements Field {
this.subfields = this.setupSubfields();
}
- setContent = (content: string) => { return };
+ setContent = (content: string, type: FieldContentType) => { return };
getContent = () => { return '' };
+ setTitle = (title: string) => { this.title = title };
+ getTitle = () => { return this.title };
+
get getSubfields() { return this.subfields };
get getAllSubfields() {
const fields: Field[] = [];
@@ -45,15 +49,16 @@ export class DynamicField implements Field {
get getDimensions() { return this.dimensions };
get getID() { return this.id };
+ get getViewType() { return this.type };
- matches = () => {
+ matches = (cols: Col[]): Array<number> => {
return [];
}
setupSubfields = (): Field[] => {
this.settings.subfields?.forEach(fieldSettings => {
let field: Field;
- const dynamicType = fieldSettings.dynamicType;
+ const dynamicType = fieldSettings.viewType;
if (dynamicType) { field = new DynamicField(fieldSettings, dynamicType, 0, this); }
@@ -78,10 +83,12 @@ export class DynamicField implements Field {
switch (this.type) {
case ViewType.CAROUSEL3D:
const carouselDoc = Docs.Create.Carousel3DDocument([], {
+ title: this.title,
});
FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
case ViewType.FREEFORM:
const freeformDoc = Docs.Create.FreeformDocument([], {
+ title: this.title,
});
FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
default:
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 0c1b6e5fc..aa1d1de33 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,23 +1,27 @@
import { Doc } from "../../../../../../fields/Doc";
+import { Col } from "../DocCreatorMenu";
import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
export interface Field {
getContent: () => string;
- setContent: (content: string) => void;
+ setContent: (content: string, type: FieldContentType) => void;
getDimensions: FieldDimensions;
getSubfields: Field[];
getAllSubfields: Field[];
getID: number;
+ getViewType: ViewType;
+ getTitle: () => string;
+ setTitle: (title: string) => void;
setupSubfields: () => Field[];
renderedDoc: (content: string) => Doc;
- matches: () => number[][];
+ matches: (cols: Col[]) => number[];
}
export type FieldSettings = {
tl: [number, number];
br: [number, number];
opts: FieldOpts;
- dynamicType?: ViewType;
+ viewType: ViewType;
subfields?: FieldSettings[];
types?: TemplateFieldType[];
sizes?: TemplateFieldSize[];
@@ -32,6 +36,8 @@ export enum FieldContentType {
export enum ViewType {
CAROUSEL3D = 'carousel3d',
FREEFORM = 'freeform',
+ STATIC = 'static',
+ DEC = 'decoration'
}
export type FieldDimensions = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index ead46d721..c389704cf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -71,74 +71,4 @@ export class FieldUtils {
return currFontSize - 1;
};
-}
-
-export class TemplateMatcher {
-
- static matchesForTemplate = (field: FieldSettings, 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(field.subfields?.length)
- .fill([])
- .map(() => []);
-
- field.subfields?.forEach((field, i) => {
- cols.forEach((col, v) => {
- if (colMatchesField(col, field)) {
- matches[i].push(v);
- }
- });
- });
-
- return matches;
- };
-
- static 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: FieldSettings[]) => {
- let validTemplates: any[] = [];
- templates.forEach(template => {
- const numFields = template.subfields?.length;
- if (!(numFields === cols.length)) return;
- const matches = TemplateMatcher.matchesForTemplate(template, cols);
- if (TemplateMatcher.maxMatches(numFields, matches) === numFields) {
- validTemplates.push('');
- }
- });
-
- validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
-
- return validTemplates;
- };
-
} \ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index efceae65a..cd1008429 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -4,10 +4,9 @@ import { FieldType } from "../../../../../../fields/ObjectField";
import { Docs, DocumentOptions } from "../../../../../documents/Documents";
import { Col } from "../DocCreatorMenu";
import { Template } from "../Template";
-import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
import { DynamicField } from "./DynamicField";
import { FieldUtils } from "./FieldUtils";
-import { Field, FieldContentType, FieldDimensions, FieldSettings } from "./Field";
+import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
export class StaticField {
private content: string;
@@ -15,6 +14,7 @@ export class StaticField {
private subfields: Field[] = [];
private id: number;
+ private title: string = '';
private settings: FieldSettings;
@@ -36,36 +36,55 @@ export class StaticField {
const fields: Field[] = [];
this.subfields?.forEach(field => {
fields.push(field);
- fields.concat(field.getAllSubfields)
+ fields.concat(field.getAllSubfields);
});
return fields;
};
get getDimensions() { return this.dimensions };
get getID() { return this.id };
+ get getViewType() { return ViewType.STATIC };
- setContent = (newContent: string) => { this.content = newContent };
+ setContent = (newContent: string, type: FieldContentType) => {
+ this.content = newContent;
+ this.contentType = type;
+ };
getContent() { return this.content };
+ setTitle = (title: string) => { this.title = title };
+ getTitle = () => { return this.title };
+
setupSubfields = (): Field[] => {
const fields: Field[] = [];
this.settings.subfields?.forEach(fieldSettings => {
let field: Field;
- const dynamicType = fieldSettings.dynamicType;
+ const dynamicType = fieldSettings.viewType;
if (dynamicType) {
field = new DynamicField(fieldSettings, dynamicType, 0, this);
} else {
field = new StaticField(fieldSettings, this, 0);
- }
+ };
fields.push(field);
});
return fields;
};
- matches = (): number[][] => {
- return [];
+ matches = (cols: Col[]): number[] => {
+ const colMatchesField = (col: Col) => {
+ return this.settings.sizes?.some(size => col.sizes?.includes(size)) && this.settings.types?.includes(col.type);
+ };
+
+ const matches: Array<number> = [];
+
+ cols.forEach((col, v) => {
+ if (colMatchesField(col)) {
+ matches.push(v);
+ }
+ });
+
+ return matches;
};
renderedDoc = (content: string): Doc => {
@@ -77,6 +96,7 @@ export class StaticField {
case FieldContentType.STRING:
const text = String(content);
const textDoc = Docs.Create.TextDocument(text, {
+ title: this.title,
text_fontColor: opts.color,
contentBold: opts.fontBold,
textTransform: opts.fontTransform,
@@ -88,6 +108,7 @@ export class StaticField {
case FieldContentType.IMAGE:
const url = String(content);
const imgDoc = Docs.Create.ImageDocument(url, {
+ title: this.title,
_layout_fitWidth: false,
});
FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index f05f61b61..486fe7f7e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,11 +1,11 @@
import { Doc } from "../../../../../fields/Doc";
import { Docs } from "../../../../documents/Documents";
+import { Col } from "./DocCreatorMenu";
import { DynamicField } from "./FieldTypes/DynamicField";
import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
import { } from "./FieldTypes/FieldUtils";
import { } from "./FieldTypes/StaticField";
-import { TemplateDocInfos } from "./TemplateBackend";
export class Template {
@@ -17,9 +17,61 @@ export class Template {
get childFields(): Field[] { return this.mainField.getSubfields };
get allFields(): Field[] { return this.mainField.getAllSubfields };
+ get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
+
+ getFieldByID = (id: number): Field => {
+ return this.allFields.filter(field => field.getID === id)[0];
+ }
setupMainField = (templateInfo: FieldSettings) => {
return new DynamicField(templateInfo, ViewType.FREEFORM, 0);
}
+ isValidTemplate = (cols: Col[]) => {
+ return this.maxMatches(this.getMatches(cols)) === this.contentFields.length;
+ }
+
+ getMatches = (cols: Col[]) => {
+ const matches: number[][] = Array(this.contentFields.length)
+ .fill([])
+ .map(() => []);
+
+ this.contentFields.forEach((field, i) => {
+ matches[i].concat(field.matches(cols));
+ });
+
+ return matches;
+ }
+
+ maxMatches = (matches: number[][]) => {
+ const fieldsCt = this.contentFields.length;
+ 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;
+ };
+
} \ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 43b0b1572..00eb8fab4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -1,4 +1,4 @@
-import { FieldOpts, FieldSettings } from "./FieldTypes/Field";
+import { FieldOpts, FieldSettings, ViewType } from "./FieldTypes/Field";
import { } from "./FieldTypes/StaticField";
export enum TemplateFieldType {
@@ -15,53 +15,24 @@ export enum TemplateFieldSize {
HUGE = 'huge',
}
-export interface TemplateDocInfos {
- title: string;
- height: number;
- width: number;
- opts: FieldOpts;
- fields: FieldSettings[];
- decorations: FieldSettings[];
-}
-
export class TemplateLayouts {
- public static get allTemplates(): TemplateDocInfos[] {
- return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as TemplateDocInfos[];
+ public static get allTemplates(): FieldSettings[] {
+ return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as FieldSettings[];
}
- public static getTemplateByTitle = (title: string): TemplateDocInfos | undefined => {
- switch (title) {
- case 'fourfield1':
- return TemplateLayouts.FourField001;
- case 'fourfield2':
- return TemplateLayouts.FourField002;
- // case 'fourfield3':
- // return TemplateLayouts.FourField003;
- case 'fourfield4':
- return TemplateLayouts.FourField004;
- case 'threefield1':
- return TemplateLayouts.ThreeField001;
- case 'threefield2':
- return TemplateLayouts.ThreeField002;
- default:
- break;
- }
-
- return undefined;
- };
-
- public static FourField001: TemplateDocInfos = {
- title: 'fourfield1',
- width: 416,
- height: 700,
+ public static FourField001: FieldSettings = {
+ tl: [0, 0],
+ br: [416, 700],
+ viewType: ViewType.FREEFORM,
opts: {
backgroundColor: '#C0B887',
cornerRounding: 20,
borderColor: '#6B461F',
borderWidth: '12',
},
- fields: [
+ subfields: [
{
+ viewType: ViewType.STATIC,
tl: [-0.95, -1],
br: [0.95, -0.85],
types: [TemplateFieldType.TEXT],
@@ -75,6 +46,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.87, -0.83],
br: [0.87, 0.2],
types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -88,6 +60,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.8, 0.2],
br: [0.8, 0.3],
types: [TemplateFieldType.TEXT],
@@ -100,6 +73,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.87, 0.37],
br: [0.87, 0.96],
types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -113,18 +87,18 @@ export class TemplateLayouts {
},
},
],
- decorations: [],
};
- public static FourField002: TemplateDocInfos = {
- title: 'fourfield2',
- width: 425,
- height: 778,
+ public static FourField002: FieldSettings = {
+ viewType: ViewType.FREEFORM,
+ tl: [0,0],
+ br: [425, 778],
opts: {
backgroundColor: '#242425',
},
- fields: [
+ subfields: [
{
+ viewType: ViewType.STATIC,
tl: [-0.83, -0.95],
br: [0.83, -0.2],
types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
@@ -136,6 +110,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.65, -0.2],
br: [0.65, -0.02],
types: [TemplateFieldType.TEXT],
@@ -149,6 +124,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.65, 0],
br: [0.65, 0.18],
types: [TemplateFieldType.TEXT],
@@ -162,6 +138,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.83, 0.2],
br: [0.83, 0.95],
types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -174,46 +151,49 @@ export class TemplateLayouts {
backgroundColor: '#242425',
},
},
- ],
- decorations: [
{
+ viewType: ViewType.DEC,
tl: [-0.8, -0.075],
br: [-0.525, 0.075],
opts: {
backgroundColor: '#F8E71C',
- //rotation: 45,
+ rotation: 45,
},
},
{
+ viewType: ViewType.DEC,
tl: [-0.3075, -0.0245],
br: [-0.2175, 0.0245],
opts: {
backgroundColor: '#F8E71C',
- //rotation: 45,
+ rotation: 45,
},
},
{
+ viewType: ViewType.DEC,
tl: [-0.045, -0.0245],
br: [0.045, 0.0245],
opts: {
backgroundColor: '#F8E71C',
- //rotation: 45,
+ rotation: 45,
},
},
{
+ viewType: ViewType.DEC,
tl: [0.2175, -0.0245],
br: [0.3075, 0.0245],
opts: {
backgroundColor: '#F8E71C',
- //rotation: 45,
+ rotation: 45,
},
},
{
+ viewType: ViewType.DEC,
tl: [0.525, -0.075],
br: [0.8, 0.075],
opts: {
backgroundColor: '#F8E71C',
- //rotation: 45,
+ rotation: 45,
},
},
],
@@ -279,17 +259,18 @@ export class TemplateLayouts {
// }]
// };
- public static FourField004: TemplateDocInfos = {
- title: 'fourfield4',
- width: 414,
- height: 583,
+ public static FourField004: FieldSettings = {
+ viewType: ViewType.FREEFORM,
+ tl: [0,0],
+ br: [414,583],
opts: {
backgroundColor: '#6CCAF0',
borderColor: '#1088C3',
borderWidth: '10',
},
- fields: [
+ subfields: [
{
+ viewType: ViewType.STATIC,
tl: [-0.86, -0.92],
br: [-0.075, -0.77],
types: [TemplateFieldType.TEXT],
@@ -303,6 +284,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [0.075, -0.92],
br: [0.86, -0.77],
types: [TemplateFieldType.TEXT],
@@ -316,6 +298,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.81, -0.64],
br: [0.81, 0.48],
types: [TemplateFieldType.VISUAL],
@@ -327,6 +310,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.86, 0.6],
br: [0.86, 0.92],
types: [TemplateFieldType.TEXT],
@@ -338,9 +322,8 @@ export class TemplateLayouts {
backgroundColor: '#F3F57D',
},
},
- ],
- decorations: [
{
+ viewType: ViewType.DEC,
tl: [-0.852, -0.67],
br: [0.852, 0.51],
opts: {
@@ -352,15 +335,16 @@ export class TemplateLayouts {
],
};
- public static ThreeField001: TemplateDocInfos = {
- title: 'threefield1',
- width: 575,
- height: 770,
+ public static ThreeField001: FieldSettings = {
+ viewType: ViewType.FREEFORM,
+ tl: [0,0],
+ br: [575, 770],
opts: {
backgroundColor: '#DDD3A9',
},
- fields: [
+ subfields: [
{
+ viewType: ViewType.STATIC,
tl: [-0.66, -0.747],
br: [0.66, 0.247],
types: [TemplateFieldType.VISUAL],
@@ -373,6 +357,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.7, 0.2],
br: [0.7, 0.46],
types: [TemplateFieldType.TEXT],
@@ -384,6 +369,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.95, 0.5],
br: [0.95, 0.95],
types: [TemplateFieldType.TEXT],
@@ -394,9 +380,8 @@ export class TemplateLayouts {
color: 'white',
},
},
- ],
- decorations: [
{
+ viewType: ViewType.DEC,
tl: [0.2, -1.32],
br: [1.8, -0.66],
opts: {
@@ -405,6 +390,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.DEC,
tl: [-1.8, -1.32],
br: [-0.2, -0.66],
opts: {
@@ -413,6 +399,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.DEC,
tl: [0.33, 0.75],
br: [1.66, 1.25],
opts: {
@@ -421,6 +408,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.DEC,
tl: [-1.66, 0.75],
br: [-0.33, 1.25],
opts: {
@@ -431,15 +419,16 @@ export class TemplateLayouts {
],
};
- public static ThreeField002: TemplateDocInfos = {
- title: 'threefield2',
- width: 477,
- height: 662,
+ public static ThreeField002: FieldSettings = {
+ viewType: ViewType.FREEFORM,
+ tl: [0,0],
+ br: [477, 662],
opts: {
backgroundColor: '#9E9C95',
},
- fields: [
+ subfields: [
{
+ viewType: ViewType.STATIC,
tl: [-0.875, -0.9],
br: [0.875, 0.7],
types: [TemplateFieldType.VISUAL],
@@ -451,6 +440,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [0.1, 0.775],
br: [0.95, 0.975],
types: [TemplateFieldType.TEXT],
@@ -465,6 +455,7 @@ export class TemplateLayouts {
},
},
{
+ viewType: ViewType.STATIC,
tl: [-0.95, 0.775],
br: [-0.1, 0.975],
types: [TemplateFieldType.TEXT],
@@ -476,9 +467,8 @@ export class TemplateLayouts {
contentXCentering: 'h-right',
},
},
- ],
- decorations: [
{
+ viewType: ViewType.DEC,
tl: [-0.025, 0.8],
br: [0.025, 0.95],
opts: {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
new file mode 100644
index 000000000..890bc6f73
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -0,0 +1,23 @@
+import { Col } from "./DocCreatorMenu";
+import { FieldSettings } from "./FieldTypes/Field";
+import { Template } from "./Template";
+import { TemplateLayouts } from "./TemplateBackend";
+
+export class TemplateManager {
+
+ templates: Template[] = [];
+
+ constructor(templateSettings: FieldSettings[]) {
+ this.templates = this.initializeTemplates(templateSettings);
+ }
+
+ initializeTemplates = (templateSettings: FieldSettings[]): Template[] => {
+ const initializedTemplates: Template[] = [];
+ templateSettings.forEach(settings => initializedTemplates.push(new Template(settings)));
+ return initializedTemplates;
+ }
+
+ getValidTemplates = (cols: Col[]): Template[] => {
+ return this.templates.filter(template => template.isValidTemplate(cols));
+ }
+} \ No newline at end of file