aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/smartdraw
diff options
context:
space:
mode:
authorA.J. Shulman <Shulman.aj@gmail.com>2025-05-11 10:46:15 -0400
committerA.J. Shulman <Shulman.aj@gmail.com>2025-05-11 10:46:15 -0400
commitb87b2105e966928518c96c7702b68c12344ffdd7 (patch)
tree84fd5ecede3af9d773c10d02908cdde27da1a759 /src/client/views/smartdraw
parent0db4583914e43e6efdba3e86a614a19956e73b5e (diff)
parent0c3f86d57225a2991920adef3a337bc13e408ac0 (diff)
Merge branch 'master' into agent-web-working
Diffstat (limited to 'src/client/views/smartdraw')
-rw-r--r--src/client/views/smartdraw/DrawingFillHandler.tsx109
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.scss1
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx83
-rw-r--r--src/client/views/smartdraw/StickerPalette.tsx61
4 files changed, 130 insertions, 124 deletions
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index c672bc718..f773957e7 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -1,8 +1,6 @@
-import { imageUrlToBase64 } from '../../../ClientUtils';
import { Doc, StrListCast } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
import { List } from '../../../fields/List';
-import { DocCast, ImageCast } from '../../../fields/Types';
+import { DocCast, ImageCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { Upload } from '../../../server/SharedMediaTypes';
import { gptDescribeImage } from '../../apis/gpt/GPT';
@@ -14,23 +12,29 @@ import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, Firefl
const DashDropboxId = '2m86iveqdr9vzsa';
export class DrawingFillHandler {
+ static authorizeDropbox = () => {
+ window.open(`https://www.dropbox.com/oauth2/authorize?client_id=${DashDropboxId}&response_type=code&token_access_type=offline&redirect_uri=http://localhost:1050/refreshDropbox`, '_blank')?.focus();
+ };
static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc) => {
- const docData = drawing[DocData];
- const tags = StrListCast(docData.tags).map(tag => tag.slice(1));
+ const tags = StrListCast(drawing.$tags).map(tag => tag.slice(1));
const styles = tags.filter(tag => FireflyStylePresets.has(tag));
- const styleDocs = !Doc.Links(drawing).length
- ? styleDoc && !tags.length
- ? [styleDoc]
- : []
- : Doc.Links(drawing)
- .map(link => Doc.getOppositeAnchor(link, drawing))
- .map(anchor => anchor && DocCast(anchor.embedContainer));
- const styleUrl = await DocumentView.GetDocImage(styleDocs.filter(doc => doc?.data instanceof ImageField).lastElement())?.then(styleImg => {
- const hrefParts = ImageCast(styleImg).url.href.split('.');
- return `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
- });
+ const styleDocs = [drawing].concat(
+ drawing,
+ ...Doc.Links(drawing)
+ .map(link => Doc.getOppositeAnchor(link, drawing))
+ .map(anchor => DocCast(anchor?.annotationOn, anchor))
+ .map(anchor => anchor!),
+ ...(styleDoc ? [styleDoc] : [])
+ );
+ const styleUrl = tags.length
+ ? undefined
+ : await DocumentView.GetDocImage(styleDocs.filter(doc => doc?.data instanceof ImageField).lastElement())?.then(styleImg => {
+ const hrefParts = ImageCast(styleImg)?.url.href.split('.');
+ return !hrefParts ? undefined : `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
+ });
return DocumentView.GetDocImage(drawing)?.then(imageField => {
- if (imageField) {
+ const href = ImageCast(imageField)?.url.href;
+ if (href) {
const aspectRatio = (drawing.width as number) / (drawing.height as number);
const dims = (() => {
if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Widescreen]) return FireflyDimensionsMap[FireflyImageDimensions.Widescreen];
@@ -38,44 +42,43 @@ export class DrawingFillHandler {
if (aspectRatio < AspectRatioLimits[FireflyImageDimensions.Portrait]) return FireflyDimensionsMap[FireflyImageDimensions.Portrait];
return FireflyDimensionsMap[FireflyImageDimensions.Square];
})();
- const { href } = ImageCast(imageField).url;
const hrefParts = href.split('.');
const structureUrl = `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
- return imageUrlToBase64(structureUrl)
- .then(gptDescribeImage)
- .then((prompt, newPrompt = user_prompt || prompt) =>
- Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl })
- .then(res => {
- const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { _width: 400, _height: 400 });
- drawing[DocData].ai_firefly_generatedDocs = genratedDocs;
- (res as Upload.ImageInformation[]).map(info =>
- Doc.AddDocToList(
- genratedDocs,
- undefined,
- Docs.Create.ImageDocument(info.accessPaths.agnostic.client, {
- ai: 'firefly',
- tags: new List<string>(['@ai']),
- title: newPrompt,
- _data_usePath: 'alternate:hover',
- data_alternates: new List<Doc>([drawing]),
- ai_firefly_prompt: newPrompt,
- _width: 500,
- data_nativeWidth: info.nativeWidth,
- data_nativeHeight: info.nativeHeight,
- }),
- undefined,
- undefined,
- true
- )
- );
- if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight);
- })
- .catch(e => {
- if (e.toString().includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + e.toString().replace(/^[^"]*/, ''))) {
- window.open(`https://www.dropbox.com/oauth2/authorize?client_id=${DashDropboxId}&response_type=code&token_access_type=offline&redirect_uri=http://localhost:1050/refreshDropbox`, '_blank')?.focus();
- } else alert(e.toString());
- })
- ); // prettier-ignore:q
+ return gptDescribeImage(user_prompt, structureUrl).then(newPrompt =>
+ Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl })
+ .then(res => {
+ const error = ('error' in res && (res.error as string)) || '';
+ if (error.includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + error.replace(/^[^"]*/, ''))) {
+ return DrawingFillHandler.authorizeDropbox();
+ }
+ const genratedDocs = DocCast(drawing.ai_generatedDocs) ?? Docs.Create.MasonryDocument([], { title: StrCast(drawing.title) + ' AI Images', _width: 400, _height: 400 });
+ drawing.$ai_generatedDocs = genratedDocs;
+ (res as Upload.ImageInformation[]).map(info =>
+ Doc.AddDocToList(
+ genratedDocs,
+ undefined,
+ Docs.Create.ImageDocument(info.accessPaths.agnostic.client, {
+ ai: 'firefly',
+ ai_prompt: newPrompt,
+ tags: new List<string>(['@ai']),
+ title: newPrompt,
+ _data_usePath: 'alternate:hover',
+ data_alternates: new List<Doc>([drawing]),
+ _width: 500,
+ data_nativeWidth: info.nativeWidth,
+ data_nativeHeight: info.nativeHeight,
+ }),
+ undefined,
+ undefined,
+ true
+ )
+ );
+ if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight);
+ })
+ .catch(e => {
+ alert(e.toString());
+ })
+ ); // prettier-ignore:q
}
});
};
diff --git a/src/client/views/smartdraw/SmartDrawHandler.scss b/src/client/views/smartdraw/SmartDrawHandler.scss
index cca7d77c7..e80f1122b 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.scss
+++ b/src/client/views/smartdraw/SmartDrawHandler.scss
@@ -73,5 +73,6 @@
.edit-box {
display: flex;
flex-direction: row;
+ color: black;
}
}
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 1cceabed3..3976ec39e 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -10,9 +10,11 @@ import { INode, parse } from 'svgson';
import { imageUrlToBase64, setupMoveUpEvents } from '../../../ClientUtils';
import { unimplementedFunction } from '../../../Utils';
import { Doc, DocListCast } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
import { InkData, InkField, InkTool } from '../../../fields/InkField';
+import { List } from '../../../fields/List';
import { BoolCast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { PointData } from '../../../pen-gestures/GestureTypes';
+import { Upload } from '../../../server/SharedMediaTypes';
import { Networking } from '../../Network';
import { GPTCallType, gptAPICall, gptDrawingColor } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -26,9 +28,6 @@ import { MarqueeView } from '../collections/collectionFreeForm';
import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveInkColor, ActiveInkDash, ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView';
import { FireflyDimensionsMap, FireflyImageData, FireflyImageDimensions } from './FireflyConstants';
import './SmartDrawHandler.scss';
-import { Upload } from '../../../server/SharedMediaTypes';
-import { PointData } from '../../../pen-gestures/GestureTypes';
-import { List } from '../../../fields/List';
export interface DrawingOptions {
text?: string;
@@ -62,7 +61,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
static Instance: SmartDrawHandler;
private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
- private _lastResponse: string = '';
private _selectedDocs: Doc[] = [];
@observable private _display: boolean = false;
@@ -98,7 +96,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
CollectionFreeForm, FormattedTextBox, StickerPalette) to define how a drawing document should be added
or removed in their respective locations (to the freeform canvas, to the sticker palette's preview, etc.)
*/
- public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => void = unimplementedFunction;
+ public AddDrawing: (doc: Doc, opts: DrawingOptions, x?: number, y?: number) => void = unimplementedFunction;
public RemoveDrawing: (useLastContainer: boolean, doc?: Doc) => void = unimplementedFunction;
/**
* This creates the ink document that represents a drawing, so it goes through the strokes that make up the drawing,
@@ -106,7 +104,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* classes to customize the way the drawing docs get created. For example, the freeform canvas has a different way of
* defining document bounds, so CreateDrawingDoc is redefined when that class calls gpt draw functions.
*/
- public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => {
+ public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
const drawing: Doc[] = [];
strokeList.forEach((stroke: [InkData, string, string]) => {
const bounds = InkField.getBounds(stroke[0]);
@@ -131,7 +129,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
drawing.push(inkDoc);
});
- return MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+ const drawn = MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+
+ drawn.$ai_drawing = true;
+ drawn.$ai_drawing_complexity = opts.complexity;
+ drawn.$ai_drawing_colored = opts.autoColor;
+ drawn.$ai_drawing_size = opts.size;
+ drawn.$ai_drawing_data = gptRes;
+ return drawn;
};
@action
@@ -147,15 +152,16 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* the regenerate popup show by user command.
*/
@action
- displayRegenerate = (x: number, y: number) => {
+ displayRegenerate = (x: number, y: number, scale: number) => {
this._selectedDocs = [DocumentView.SelectedDocs()?.lastElement()];
[this._pageX, this._pageY] = [x, y];
+ this._scale = scale;
this._display = false;
this.ShowRegenerate = true;
this._showEditBox = false;
- const docData = this._selectedDocs[0][DocData];
- this._lastResponse = StrCast(docData.drawingData);
- this._lastInput = { text: StrCast(docData.ai_drawing_input), complexity: NumCast(docData.ai_drawing_complexity), size: NumCast(docData.ai_drawing_size), autoColor: BoolCast(docData.ai_drawing_colored), x: this._pageX, y: this._pageY };
+ const docData = this._selectedDocs[0];
+ this._regenInput = StrCast(docData.$ai_prompt, StrCast(docData.title));
+ this._lastInput = { text: StrCast(docData.$ai_prompt), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
};
/**
@@ -169,9 +175,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this._isLoading = false;
this._showOptions = false;
this._userInput = '';
- this._complexity = 5;
- this._size = 350;
- this._autoColor = true;
Doc.ActiveTool = InkTool.None;
}
};
@@ -185,7 +188,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this.ShowRegenerate = false;
this._isLoading = false;
this._regenInput = '';
- this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
}
};
@@ -209,7 +211,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this._isLoading = true;
this._canInteract = false;
if (this.ShowRegenerate) {
- await this.regenerate(this._selectedDocs, undefined, undefined, this._regenInput).then(action(() => (this._showEditBox = false)));
+ this._lastInput.x = X;
+ this._lastInput.y = Y;
+ await this.regenerate(this._selectedDocs).then(action(() => (this._showEditBox = false)));
} else {
this._showOptions = false;
try {
@@ -235,13 +239,15 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
drawWithGPT = async (screenPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
if (input) {
- this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: screenPt.X, y: screenPt.Y };
+ this._lastInput = { text: input, complexity, size, autoColor, x: screenPt.X, y: screenPt.Y };
const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true);
if (res) {
const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, false, autoColor);
const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
- drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res, screenPt.X, screenPt.Y);
- drawingDoc && this._selectedDocs.push(drawingDoc);
+ if (drawingDoc) {
+ this.AddDrawing(drawingDoc, this._lastInput, screenPt.X, screenPt.Y);
+ this._selectedDocs.push(drawingDoc);
+ }
return strokeData;
} else {
console.error('GPT call failed');
@@ -256,7 +262,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
createImageWithFirefly = (input: string, seed?: number): Promise<FireflyImageData | Doc | undefined> => {
this._lastInput.text = input;
return SmartDrawHandler.CreateWithFirefly(input, this._imgDims, seed).then(doc => {
- doc instanceof Doc && this.AddDrawing(doc, this._lastInput, input, this._pageX, this._pageY);
+ doc instanceof Doc && this.AddDrawing(doc, this._lastInput, this._pageX, this._pageY);
return doc;
});
}; /**
@@ -302,8 +308,8 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
_width: Math.min(400, dims.width),
_height: (Math.min(400, dims.width) * dims.height) / dims.width,
ai: 'firefly',
- ai_firefly_seed: +(newseed ?? 0),
- ai_firefly_prompt: input,
+ ai_prompt_seed: +(newseed ?? 0),
+ ai_prompt: input,
});
})
.catch(e => {
@@ -317,33 +323,30 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* @param doc the drawing Docs to regenerate
*/
@action
- regenerate = (drawingDocs: Doc[], lastInput?: DrawingOptions, lastResponse?: string, regenInput?: string, changeInPlace?: boolean) => {
- if (lastInput) this._lastInput = lastInput;
- if (lastResponse) this._lastResponse = lastResponse;
+ regenerate = (drawingDocs: Doc[], regenInput?: string, changeInPlace?: boolean) => {
if (regenInput) this._regenInput = regenInput;
return Promise.all(
drawingDocs.map(async doc => {
switch (doc.type) {
case DocumentType.IMG: {
const func = changeInPlace ? this.recreateImageWithFirefly : this.createImageWithFirefly;
- const newPrompt = doc.ai_firefly_prompt ? `${doc.ai_firefly_prompt} ~~~ ${this._regenInput}` : this._regenInput;
- return this._regenInput ? func(newPrompt, NumCast(doc?.ai_firefly_seed)) : func(this._lastInput.text || StrCast(doc.ai_firefly_prompt));
+ const newPrompt = doc.ai_prompt && doc.ai_prompt !== this._regenInput ? `${doc.ai_prompt} ~~~ ${this._regenInput}` : this._regenInput;
+ return this._regenInput ? func(newPrompt, NumCast(doc?.ai_prompt_seed)) : func(this._lastInput.text || StrCast(doc.ai_prompt));
}
case DocumentType.COL: {
try {
const res = await (async () => {
if (this._regenInput) {
- const prompt = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`;
+ const prompt = `This is your previously generated svg code: ${doc.$ai_drawing_data} for the user input "${doc.ai_prompt}". Please regenerate it with the provided specifications.`;
this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`;
return gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true);
}
- return gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true);
+ return gptAPICall(`"${doc.$ai_prompt}", "${doc.$ai_drawing_complexity}", "${doc.$ai_drawing_size}"`, GPTCallType.DRAW, undefined, true);
})();
if (res) {
- const strokeData = await this.parseSvg(res, { X: this._lastInput.x ?? 0, Y: this._lastInput.y ?? 0 }, true, lastInput?.autoColor || this._autoColor);
- this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(true, doc);
+ const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, true, this._autoColor);
const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
- drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res);
+ drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, this._lastInput.x, this._lastInput.y);
} else {
console.error('GPT call failed');
}
@@ -364,7 +367,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
if (svg) {
- this._lastResponse = svg[0];
const svgObject = await parse(svg[0]);
console.log(res, svgObject);
const svgStrokes: INode[] = svgObject.children;
@@ -399,12 +401,12 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
colorWithGPT = async (drawing: Doc) => {
const img = await DocumentView.GetDocImage(drawing);
- const { href } = ImageCast(img).url;
+ const { href } = ImageCast(img)?.url ?? { href: '' };
const hrefParts = href.split('.');
const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`;
try {
const hrefBase64 = await imageUrlToBase64(hrefComplete);
- const strokes = DocListCast(drawing[DocData].data);
+ const strokes = DocListCast(drawing.$data);
const coords: string[] = [];
strokes.forEach((stroke, i) => {
const inkingStroke = DocumentView.getDocumentView(stroke)?.ComponentView as InkingStroke;
@@ -423,14 +425,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
colorStrokes = undoable((res: string, drawing: Doc) => {
const colorList = res.match(/\{.*?\}/g);
- const strokes = DocListCast(drawing[DocData].data);
+ const strokes = DocListCast(drawing.$data);
colorList?.forEach((colors, index) => {
const strokeAndFill = colors.match(/#[0-9A-Fa-f]{6}/g);
if (strokeAndFill && strokeAndFill.length == 2) {
- strokes[index][DocData].color = strokeAndFill[0];
+ strokes[index].$color = strokeAndFill[0];
const inkStroke = DocumentView.getDocumentView(strokes[index])?.ComponentView as InkingStroke;
const { inkData } = inkStroke.inkScaledData();
- InkingStroke.IsClosed(inkData) ? (strokes[index][DocData].fillColor = strokeAndFill[1]) : (strokes[index][DocData].fillColor = undefined);
+ InkingStroke.IsClosed(inkData) ? (strokes[index].$fillColor = strokeAndFill[1]) : (strokes[index].$fillColor = undefined);
}
});
}, 'color strokes');
@@ -577,6 +579,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
type="text"
autoFocus
value={this._userInput}
+ onPointerDown={e => e.stopPropagation()}
onChange={action(e => this._canInteract && (this._userInput = e.target.value))}
placeholder="Enter item to draw"
onKeyDown={this.handleKeyPress}
@@ -664,7 +667,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
<div className="regenerate-box">
<IconButton
tooltip="Regenerate"
- icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
+ icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
color={SettingsManager.userColor}
onClick={() => this.handleSendClick(this._pageX, this._pageY)}
/>
diff --git a/src/client/views/smartdraw/StickerPalette.tsx b/src/client/views/smartdraw/StickerPalette.tsx
index e3305851a..6ef3d26ad 100644
--- a/src/client/views/smartdraw/StickerPalette.tsx
+++ b/src/client/views/smartdraw/StickerPalette.tsx
@@ -9,8 +9,7 @@ import ReactLoading from 'react-loading';
import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils';
import { emptyFunction, numberRange } from '../../../Utils';
import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
-import { ImageCast, NumCast } from '../../../fields/Types';
+import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
@@ -26,7 +25,7 @@ import { DrawingOptions, SmartDrawHandler } from './SmartDrawHandler';
import './StickerPalette.scss';
interface StickerPaletteProps {
- Document: Doc;
+ Doc: Doc;
}
enum StickerPaletteMode {
@@ -57,10 +56,10 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
if (!doc.savedAsSticker) {
const docView = DocumentView.getDocumentView(doc);
await docView?.ComponentView?.updateIcon?.(true);
- const { clone } = await Doc.MakeClone(doc);
+ const { clone } = Doc.MakeClone(doc);
clone.title = doc.title;
- const image = ImageCast(doc.icon, ImageCast(clone[Doc.LayoutFieldKey(clone)]))?.url?.href;
- Doc.AddDocToList(Doc.MyStickers, 'data', makeUserTemplateButtonOrImage(clone, image));
+ const image = ImageCast(doc.icon, ImageCast(clone[Doc.LayoutDataKey(clone)]))?.url?.href;
+ Doc.MyStickers && Doc.AddDocToList(Doc.MyStickers, 'data', makeUserTemplateButtonOrImage(clone, image));
doc.savedAsSticker = true;
}
};
@@ -133,7 +132,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
this._canInteract = true;
this._opts = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 };
this._gptRes = [];
- this._props.Document[DocData].data = undefined;
+ this._props.Doc.$data = undefined;
});
/**
@@ -143,14 +142,14 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
@undoBatch
generateDrawings = action(() => {
this._isLoading = true;
- const prevDrawings = DocListCast(this._props.Document[DocData].data);
- this._props.Document[DocData].data = undefined;
+ const prevDrawings = DocListCast(this._props.Doc.$data);
+ this._props.Doc.$data = undefined;
SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
this._canInteract = false;
Promise.all(
- numberRange(3).map(i => {
+ numberRange(3).map(() => {
return this._showRegenerate
- ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._opts, this._gptRes[i], this._userInput)
+ ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._userInput)
: SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput, this._opts.complexity || 0, this._opts.size || 0, !!this._opts.autoColor);
})
).then(() => {
@@ -162,10 +161,10 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
});
@action
- addDrawing = (drawing: Doc, opts: DrawingOptions, gptRes: string) => {
- this._gptRes.push(gptRes);
- drawing[DocData].freeform_fitContentsToBox = true;
- Doc.AddDocToList(this._props.Document, 'data', drawing);
+ addDrawing = (drawing: Doc) => {
+ this._gptRes.push(StrCast(drawing.$ai_drawing_data));
+ drawing.$freeform_fitContentsToBox = true;
+ Doc.AddDocToList(this._props.Doc, 'data', drawing);
};
/**
@@ -174,19 +173,18 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
* presses the "save drawing" button.
*/
saveDrawing = () => {
- const cIndex = NumCast(this._props.Document.carousel_index);
- const focusedDrawing = DocListCast(this._props.Document.data)[cIndex];
- const docData = focusedDrawing[DocData];
- docData.title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
- docData.ai_drawing_input = this._opts.text;
- docData.ai_drawing_complexity = this._opts.complexity;
- docData.ai_drawing_colored = this._opts.autoColor;
- docData.ai_drawing_size = this._opts.size;
- docData.ai_drawing_data = this._gptRes[cIndex];
- docData.ai = 'gpt';
+ const cIndex = NumCast(this._props.Doc.carousel_index);
+ const focusedDrawing = DocListCast(this._props.Doc.data)[cIndex];
+ focusedDrawing.$title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
+ focusedDrawing.$ai_prompt = this._opts.text;
+ focusedDrawing.$ai_drawing_complexity = this._opts.complexity;
+ focusedDrawing.$ai_drawing_colored = this._opts.autoColor;
+ focusedDrawing.$ai_drawing_size = this._opts.size;
+ focusedDrawing.$ai_drawing_data = this._gptRes[cIndex];
+ focusedDrawing.$ai = 'gpt';
focusedDrawing.width = this._opts.size;
- docData.x = this._opts.x;
- docData.y = this._opts.y;
+ focusedDrawing.x = this._opts.x;
+ focusedDrawing.y = this._opts.y;
StickerPalette.addToPalette(focusedDrawing).then(() => this.resetPalette(true));
};
@@ -315,7 +313,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
<>
{this.renderCreateInput()}
{this.renderCreateOptions()}
- {this.renderDoc(this._props.Document, (r: DocumentView) => {
+ {this.renderDoc(this._props.Doc, (r: DocumentView) => {
this._docCarouselView = r;
})}
<div className="palette-buttons">
@@ -329,9 +327,10 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
);
renderPaletteView = () => (
<>
- {this.renderDoc(Doc.MyStickers, (r: DocumentView) => {
- this._docView = r;
- })}
+ {Doc.MyStickers &&
+ this.renderDoc(Doc.MyStickers, (r: DocumentView) => {
+ this._docView = r;
+ })}
<Button text="Add" icon={<FontAwesomeIcon icon="square-plus" />} color={SettingsManager.userColor} onClick={() => this.setPaletteMode(StickerPaletteMode.create)} />
</>
);