diff options
author | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2024-09-04 04:14:59 -0400 |
---|---|---|
committer | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2024-09-04 04:14:59 -0400 |
commit | b4e4cca578747c987efde7fa8c14299790f3ee02 (patch) | |
tree | b9b1a9df83e6bb2133162e5a5493f99174b28679 /src | |
parent | 0581f0943aad45fae70bb34e61fa219121d64b8f (diff) |
stuff
Diffstat (limited to 'src')
-rw-r--r-- | src/client/apis/gpt/GPT.ts | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DataVizBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.scss | 15 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx | 261 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 23 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.scss | 1 |
6 files changed, 232 insertions, 71 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index ba8106c4d..6befad310 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -56,7 +56,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { temp: 0, prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct', }, - template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template, # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{0:”Name”, 1:”Image”, 2:”Caption”, 3:”Position”, 4:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. Do this for each template whose fields are described. The descriptions are as follows: ' }, + template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template, # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:' }, vizsum: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide brief descriptions for columns in a dataset based on example rows. Your descriptions should be geared towards how each column’s data might fit together into a visual template. Would they make good titles, main focuses, captions, descriptions, etc. Pay special attention to connections between columns, i.e. is there one column that specifically seems to describe/be related to another more than the rest? You should provide your analysis in JSON format like so: {“col1”:”description”, “col2”:”description”, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'}, vizsum2: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“title (of column)”:{“type”:”text”, “size”:”small”}, “title (of column)”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'} }; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 6888d5f1e..e8235ce1a 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -712,6 +712,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const targetKey = StrCast(templateInfo.doc!.layout_fieldKey, 'layout'); const applied = this.ApplyTemplateTo(templateInfo.doc!, target, targetKey, templateInfo.doc!.title + `${row}`); target.layout_fieldKey = targetKey; + //this.applyImagesTo(target, fields); return applied; }); diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss index c93798979..1f81bf960 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss @@ -307,8 +307,11 @@ } .docCreatorMenu-preview-image{ - width: 105px; - height: 105px; + background-color: transparent; + height: 100px; + width: 100px; + display: block; + object-fit: contain; border-radius: 5px; } @@ -411,10 +414,16 @@ } .section-reveal-options { - margin: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-right: 0px; margin-left: auto; border: 0px; background: none; + + &.float-right { + float: right; + } } .docCreatorMenu-section-title { diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index e36adc40a..191b387c4 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -59,7 +59,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { @observable _layoutPreviewScale: number = 1; @observable _savedLayouts: DataVizTemplateLayout[] = []; - @observable _GPTTemplates: Doc[] = []; + @observable _suggestedTemplates: Doc[] = []; @observable _GPTOpt: boolean = false; @observable _userPrompt: string = ''; @observable _callCount: number = 0; @@ -99,7 +99,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz }; @action setTemplateDocs = (docs: Doc[]) => {this._templateDocs = docs.map(doc => doc.annotationOn ? DocCast(doc.annotationOn):doc)}; - @action setGPTTemplates = (docs: Doc[]) => {this._GPTTemplates = docs}; + @action setGSuggestedTemplates = (docs: Doc[]) => {this._suggestedTemplates = docs}; @computed get docsToRender() { return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; @@ -198,7 +198,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { document.addEventListener('pointerdown', this.onPointerDown, true); document.addEventListener('pointerup', this.onPointerUp); this._disposers.templates = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon)); - this._disposers.gpt = reaction(() => this._GPTTemplates.slice(), (docs) => docs.map(this.getIcon)); + this._disposers.gpt = reaction(() => this._suggestedTemplates.slice(), (docs) => docs.map(this.getIcon)); //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')}) this._disposers.lightbox = reaction(() => LightboxView.LightboxDoc(), doc => { doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu()}); //this._disposers.fields = reaction(() => this._dataViz?.axes, cols => this._selectedCols = cols?.map(col => { return {title: col, type: '', desc: ''}})) @@ -233,7 +233,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { @action openMenu = () => { - const allTemplates = this._templateDocs.concat(this._GPTTemplates); + const allTemplates = this._templateDocs.concat(this._suggestedTemplates); this._shouldDisplay = true; this.updateIcons(allTemplates); }; @@ -357,7 +357,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const res = await gptAPICall(prompt, GPTCallType.TEMPLATE); if (res && this._callCount === origCount) { - this._GPTTemplates = []; + this._suggestedTemplates = []; this._GPTLoading = false; const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res); this.createGeneratedTemplates(templates, 500, 500); @@ -389,14 +389,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { GPTTemplates.push(template); }); - setTimeout(() => {this.setGPTTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100); + setTimeout(() => {this.setGSuggestedTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100); this.forceUpdate(); }; editTemplate = (doc: Doc) => { //this.closeMenu(); - DocumentViewInternal.addDocTabFunc(doc, OpenWhere.lightboxAlways); + DocumentViewInternal.addDocTabFunc(doc, OpenWhere.addRight); DocumentView.DeselectAll(); Doc.UnBrushDoc(doc); }; @@ -419,20 +419,22 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; // mainCollection.addDocument(doc); - const temp = TemplateLayouts.FourField001; + // const temp = TemplateLayouts.FourField001; - const img: Col = {type: TemplateFieldType.VISUAL, title: 'Image', desc: 'description whpoo', size: TemplateFieldSize.LARGE}; - const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description hey', size: TemplateFieldSize.TINY}; - const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: TemplateFieldSize.TINY}; - const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: TemplateFieldSize.LARGE}; + // const img: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description whpoo', size: TemplateFieldSize.LARGE, defaultContent: ''}; + // const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Image', desc: 'description hey', size: TemplateFieldSize.TINY}; + // const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: TemplateFieldSize.TINY, defaultContent: ''}; + // const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: TemplateFieldSize.LARGE, defaultContent: 'This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well. This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well. This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well.'}; // const assignments = {'0': img, '1': capt1, '2': capt2, '3': desc} // this.createEmptyTemplate(temp, assignments); + // console.log(this.findValidTemplates(this.fieldsInfos, TemplateLayouts.allTemplates)); - this.generatePresetTemplates(this.findValidTemplates(this.fieldsInfos, TemplateLayouts.allTemplates), this.fieldsInfos); // console.log(this._dataViz?.colsInfo.get("IMG")?.size, this._dataViz?.colsInfo.get("IMG")?.type) // console.log(this.fieldsInfos) + + }; @action addField = () => { @@ -492,7 +494,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const colMatchesField = (col: Col, field : Field) => { return field.sizes?.includes(col.size) && field.types?.includes(col.type) }; const matches: number[][] = Array(template.fields.length).fill([]).map(() => []); - console.log(matches) + template.fields.forEach((field, i) => { cols.forEach((col, v) => { if (colMatchesField(col, field)) { @@ -507,11 +509,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { maxMatches = (fieldsCt: number, matches: number[][]) => { const used: boolean[] = Array(fieldsCt).fill(false); const mt: number[] = Array(fieldsCt).fill(-1); + console.log(fieldsCt, matches) const augmentingPath = (v: number): boolean => { if (used[v]) return false; used[v] = true; for (const to of matches[v]) { + console.log(mt[to]); if (mt[to] === -1 || augmentingPath(mt[to])) { mt[to] = v; return true; @@ -538,7 +542,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => { let validTemplates: any[] = []; templates.forEach(template => { - const numFields = template.fields.length; + 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); @@ -546,6 +551,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }) validTemplates = validTemplates.map(title => TemplateLayouts.fieldByTitle(title)); + + console.log(validTemplates); return validTemplates; }; @@ -571,7 +578,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { // return new Doc; // } - createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: string]: Col}) => { + createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: string]: Col}): Doc => { const fields: Doc[] = []; Object.entries(assignments).forEach(([f, col]) => { @@ -618,12 +625,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; mainCollection.addDocument(renderedTemplate); + return renderedTemplate; }; compileFieldDescriptions = (templates: TemplateDocInfos[]): string => { let descriptions: string = ''; templates.forEach(template => { - descriptions += `---------- Description of template ${template.title}'s fields: ` + descriptions += `---------- NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: ` template.fields.forEach((field, index) => { descriptions += `{Field #${index}: ${field.description}} ` }); @@ -633,7 +641,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }; compileColDescriptions = (cols: Col[]): string => { - let descriptions: string = ''; + let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:'; cols.forEach(col => descriptions += `{title: ${col.title}, size: ${col.size}, type: ${col.type}, descreiption: ${col.desc}} `); return descriptions; @@ -648,6 +656,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const inputText = fieldDescriptions.concat(colDescriptions); + console.log(inputText); ++this._callCount; const origCount = this._callCount; @@ -660,6 +669,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { if (res && this._callCount === origCount) { this._GPTLoading = false; + + console.log(res); + const assignments: {[templateTitle: string]: {[field: string]: string}} = JSON.parse(res); const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = []; Object.entries(assignments).forEach(([tempTitle, assignment]) => { @@ -681,11 +693,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return []; }; - generatePresetTemplates = async(templates: TemplateDocInfos[], cols: Col[]) => { + generatePresetTemplates = async() => { + const cols = this.fieldsInfos; + const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates); const assignments: [TemplateDocInfos, {[field: number]: Col}][] = await this.assignColsToFields(templates, cols); + const renderedTemplates: Doc[] = []; assignments.forEach(([template, assignments]) => { - this.createEmptyTemplate(template, assignments); + renderedTemplates.push(this.createEmptyTemplate(template, assignments)); }); + + setTimeout(() => {this.setGSuggestedTemplates(renderedTemplates)}); } get templatesPreviewContents(){ @@ -699,7 +716,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { <div className='docCreatorMenu-section' style={{height: this._GPTOpt ? 200 : 200}}> <div className='docCreatorMenu-section-topbar'> <div className='docCreatorMenu-section-title'>Suggested Templates</div> - <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}> + <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._menuContent = 'dashboard')}> <FontAwesomeIcon icon='gear'/> </button> </div> @@ -709,7 +726,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} /> </div> ) : ( - this._GPTTemplates?.map(doc => + this._suggestedTemplates?.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => <div className='docCreatorMenu-preview-window' @@ -730,10 +747,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { </div> <div className='docCreatorMenu-GPT-options'> <div className='docCreatorMenu-GPT-options-container'> - <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}> + <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generatePresetTemplates())}> <FontAwesomeIcon icon='arrows-rotate'/> </button> - <input className='docCreatorMenu-GPT-prompt-input' placeholder='Additional prompt:' onChange={e => this._userPrompt = e.target.value}/> </div> {this._GPTOpt ? GPTOptions : null } </div> @@ -1036,9 +1052,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return ( <div className='docCreatorMenu-dashboard-view'> <div className='topbar'> - <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}> - <FontAwesomeIcon icon='plus'/> - </button> + <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}> + <FontAwesomeIcon icon='plus'/> + </button> + <button className='docCreatorMenu-menu-button section-reveal-options float-right' onPointerDown={e => this.setUpButtonClick(e, () => this._menuContent = 'templates')}> + <FontAwesomeIcon icon='arrow-left'/> + </button> </div> {this.fieldsInfos.map((field, index) => <div className='field-panel' id={`${index}`}> @@ -1261,12 +1280,12 @@ interface TemplateOpts extends FieldOpts { export class FieldFuncs { - private static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => { + 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 * (uppercase ? 1.25 : 1); + let currTextHeight = currFontSize * rowsCount * 2; while (currTextHeight <= contHeight) { let wordIndex = 0; @@ -1276,7 +1295,8 @@ export class FieldFuncs { while (wordIndex < words.length) { const word = words[wordIndex]; - const wordWidth = word.length * currFontSize; + const wordWidth = word.length * currFontSize * .5; + //console.log(wordWidth) if (currentRowWidth + wordWidth <= contWidth) { currentRowWidth += wordWidth; @@ -1291,11 +1311,11 @@ export class FieldFuncs { } } - wordIndex++; + wordIndex++; } - currTextHeight = rowsCount * currFontSize * (uppercase ? 1.25 : 1); - //console.log(rowsCount, currTextHeight) + currTextHeight = rowsCount * currFontSize * 2; + //console.log(rowsCount, currFontSize, currTextHeight) currFontSize += 1; } @@ -1312,6 +1332,7 @@ export class FieldFuncs { const width = r - l; const height = b - t; const coord = {x: l, y: t}; + console.log(coords, parentWidth, parentHeight, height); return {width, height, coord}; } @@ -1378,6 +1399,7 @@ export class FieldFuncs { title: title, x: coord.x, y: coord.y, + _layout_fitWidth: false, backgroundColor: opts.backgroundColor ?? '', _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px', borderColor: opts.borderColor, @@ -1386,6 +1408,8 @@ export class FieldFuncs { _rotation: opts.rotation, }); + //setTimeout(() => {doc._height = height; doc._width = width}, 10); + return doc; } @@ -1415,8 +1439,12 @@ export class TemplateLayouts { 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; } @@ -1427,11 +1455,11 @@ export class TemplateLayouts { public static FourField001: TemplateDocInfos = { title: 'fourfield1', width: 416, - height: 721, + height: 700, opts: { - backgroundColor: '#7B8D62', + backgroundColor: '#C0B887', cornerRounding: 20, - borderColor: '#642B00', + borderColor: '#6B461F', borderWidth: '12', }, fields: [{ @@ -1454,13 +1482,13 @@ export class TemplateLayouts { description: 'The main focus of the template; could be an image, long text, etc.', opts: { cornerRounding: 20, - borderColor: '#642B00', + borderColor: '#8F5B25', borderWidth: '6', backgroundColor: '#CECAB9', } }, { tl: [-.8, .2], - br: [.8, .35], + br: [.8, .3], types: [TemplateFieldType.TEXT], sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], description: 'A caption for field #2, very short to short text that contextualizes the content of field #2', @@ -1474,10 +1502,10 @@ export class TemplateLayouts { br: [.87, .96], types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL], sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], - description: 'A medium-sized field for medium/long text or a secondary image that complements the main focus.', + description: 'A medium-sized field for medium/long text.', opts: { cornerRounding: 15, - borderColor: '#642B00', + borderColor: '#8F5B25', borderWidth: '6', backgroundColor: '#CECAB9', } @@ -1497,28 +1525,28 @@ export class TemplateLayouts { br: [.83, -.2], types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT], sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE], - description: '', + description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.', opts: { borderWidth: '8', borderColor: '#F8E71C', } }, { - tl: [-.45, -.18], - br: [.45, 0], + tl: [-.65, -.2], + br: [.65, -.02], types: [TemplateFieldType.TEXT], - sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], - description: '', + sizes: [TemplateFieldSize.TINY], + description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: 'transparent', color: 'white', contentXCentering: 'h-center' } }, { - tl: [-.45, 0], - br: [.45, .18], + tl: [-.65, 0], + br: [.65, .18], types: [TemplateFieldType.TEXT], - sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], - description: '', + sizes: [TemplateFieldSize.TINY], + description: 'A tiny field for just a word or two of plain text.', opts: { backgroundColor: 'transparent', color: 'white', @@ -1529,11 +1557,12 @@ export class TemplateLayouts { br: [.83, .95], types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL], sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], - description: '', + description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus, or share focus with field 1.', opts: { borderWidth: '8', borderColor: '#F8E71C', - backgroundColor: '#242425' + color: 'white', + backgroundColor: '#242425', } }], decorations: [{ @@ -1612,7 +1641,8 @@ export class TemplateLayouts { description: '', opts: { backgroundColor: 'transparent', - color: 'white', + color: 'red', + fontTransform: 'uppercase', contentXCentering: 'h-left' } }, { @@ -1635,6 +1665,72 @@ export class TemplateLayouts { }] }; + public static FourField004: TemplateDocInfos = { + title: 'fourfield4', + width: 414, + height: 583, + opts: { + backgroundColor: '#6CCAF0', + borderColor: '#1088C3', + borderWidth: '10' + }, + fields: [{ + tl: [-.86, -.92], + br: [-.075, -.77], + types: [TemplateFieldType.TEXT], + sizes: [TemplateFieldSize.TINY], + description: 'A tiny field for just a word or two of plain text.', + opts: { + backgroundColor: '#E2B4F5', + borderWidth: '9', + borderColor: '#9222F1', + contentXCentering: 'h-center' + } + }, { + tl: [.075, -.92], + br: [.86, -.77], + types: [TemplateFieldType.TEXT], + sizes: [TemplateFieldSize.TINY], + description: 'A tiny field for just a word or two of plain text.', + opts: { + backgroundColor: '#F5B4DD', + borderWidth: '9', + borderColor: '#E260F3', + contentXCentering: 'h-center' + } + }, { + tl: [-.81, -.64], + br: [.81, .48], + types: [TemplateFieldType.VISUAL], + sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], + description: 'A large to huge field for visual content that is the main content of the template.', + opts: { + borderWidth: '16', + borderColor: '#A2BD77', + } + }, { + tl: [-.86, .6], + br: [.86, .92], + types: [TemplateFieldType.TEXT], + sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE], + description: 'A medium to large field for text that describes the visual content above', + opts: { + borderWidth: '9', + borderColor: '#F0D601', + backgroundColor: '#F3F57D', + } + }], + decorations: [{ + tl: [-.852, -.67], + br: [.852, .51], + opts: { + backgroundColor: 'transparent', + borderColor: '#007C0C', + borderWidth: '10', + } + }] + }; + public static ThreeField001: TemplateDocInfos = { title: 'threefield1', width: 575, @@ -1646,8 +1742,8 @@ export class TemplateLayouts { tl: [-.66, -.747], br: [.66, .247], types: [TemplateFieldType.VISUAL], - sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], - description: '', + sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], + description: 'A medium to large field for visual content that is the central focus.', opts: { borderColor: 'yellow', borderWidth: '8', @@ -1670,7 +1766,7 @@ export class TemplateLayouts { br: [.7, .46], types: [TemplateFieldType.TEXT], sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], - description: '', + description: 'A very small text field for one to a few words. A good caption for the image.', opts: { backgroundColor: 'transparent', contentXCentering: 'h-center', @@ -1680,7 +1776,7 @@ export class TemplateLayouts { br: [.95, .95], types: [TemplateFieldType.TEXT], sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE], - description: '', + description: 'A medium to large text field for a thorough description of the image. ', opts: { backgroundColor: 'transparent', color: 'white' @@ -1717,6 +1813,59 @@ export class TemplateLayouts { }] }; + public static ThreeField002: TemplateDocInfos = { + title: 'threefield2', + width: 477, + height: 662, + opts: { + backgroundColor: '#9E9C95' + }, + fields: [{ + tl: [-.95, .8], + br: [-.1, .95], + types: [TemplateFieldType.VISUAL], + sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE], + description: '', + opts: { + backgroundColor: 'transparent', + color: 'white', + contentXCentering: 'h-right', + } + }, { + tl: [.1, .8], + br: [.95, .95], + types: [TemplateFieldType.TEXT], + sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], + description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.', + opts: { + backgroundColor: 'transparent', + color: 'red', + fontTransform: 'uppercase', + fontBold: true, + contentXCentering: 'h-left' + } + }, { + tl: [0, -.9], + br: [.85, -.66], + types: [TemplateFieldType.TEXT], + sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL], + description: 'A very small text field for one to a few words. The content should contextualize field 2.', + opts: { + backgroundColor: 'transparent', + contentXCentering: 'h-right' + } + }], + decorations: [{ + tl: [-.025, .8], + br: [.025, .95], + opts: { + backgroundColor: '#E0E0DA', + } + }] + }; + + + // public static FourField002: TemplateDocInfos = { // width: 450, // height: 600, diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index faea05104..53aa7171f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -123,15 +123,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { { fireImmediately: true, delay: 1000 } ); const { layoutDoc } = this; - this._disposers.path = reaction( - () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }), - ({ nativeSize, width }) => { - if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) { - this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth; - } - }, - { fireImmediately: true } - ); + // this._disposers.path = reaction( + // () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }), + // ({ nativeSize, width }) => { + // if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) { + // this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth; + // } + // }, + // { fireImmediately: true } + // ); this._disposers.scroll = reaction( () => this.layoutDoc.layout_scrollTop, sTop => { @@ -394,7 +394,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { alt="" key="paths" src={srcpath} - style={{ transform, transformOrigin }} + style={{ transform, transformOrigin, objectFit: 'fill', height: '100%' }} onError={action(e => { this._error = e.toString(); })} @@ -456,6 +456,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { savedAnnotations = () => this._savedAnnotations; render() { + console.log('img', this._props.PanelWidth(), this._props.PanelHeight()) TraceMobx(); const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding); const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad; @@ -475,7 +476,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { })} style={{ width: this._props.PanelWidth() ? undefined : `100%`, - height: this._props.PanelWidth() ? undefined : `100%`, + height: this._props.PanelHeight() ? undefined : `100%`, pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, overflow: this.layoutDoc.layout_fitWidth || this._props.fitWidth?.(this.Document) ? 'auto' : undefined, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index d6fd81f83..72d550c7e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -79,6 +79,7 @@ audiotag:hover { transform-origin: left top; top: 0; left: 0; + } .formattedTextBox-cont { |