aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2025-01-08 02:26:53 -0500
committereleanor-park <eleanor_park@brown.edu>2025-01-08 02:26:53 -0500
commit45e22be891331e2d6a381e988c7abd29af3e1399 (patch)
tree03211b371b3fa51c6be603ac9d27264558d79423
parent7ec6b821746eeaf139799044013b45578619a7ed (diff)
added componentAIView for collections
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx226
-rw-r--r--src/client/views/nodes/ImageBox.tsx33
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx2
3 files changed, 168 insertions, 93 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9af698ec7..af82724ef 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,5 +1,5 @@
import { Bezier } from 'bezier-js';
-import { Colors } from 'browndash-components';
+import { Button, Colors, Type } from 'browndash-components';
import { Property } from 'csstype';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -67,6 +67,8 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable
import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors';
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
+import ReactLoading from 'react-loading';
+import { SettingsManager } from '../../../util/SettingsManager';
@observer
class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> {
@@ -2186,84 +2188,160 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
</div>
);
}
- render() {
- TraceMobx();
+
+ @observable private _regenInput = '';
+ @observable private _canInteract = true;
+ @observable private _regenerateLoading = false;
+
+ componentAIViewHistory = () => {
return (
- <div
- className="collectionfreeformview-container"
- id={this._paintedId}
- ref={r => {
- this.createDashEventsTarget(r);
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- // prevent wheel events from passivly propagating up through containers
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- r?.addEventListener('mouseleave', this.onMouseLeave);
- r?.addEventListener('mouseenter', this.onMouseEnter);
- }}
- onWheel={this.onPointerWheel}
- onClick={this.onClick}
- onPointerDown={this.onPointerDown}
- onPointerMove={this.onCursorMove}
- onDrop={this.onExternalDrop}
- onDragOver={e => e.preventDefault()}
- onContextMenu={this.onContextMenu}
- style={{
- pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : this._props.pointerEvents?.(),
- textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
- transform: `scale(${this.nativeDimScaling})`,
- width: `${100 / this.nativeDimScaling}%`,
- height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`,
- }}>
- {Doc.ActiveTool === InkTool.Eraser && Doc.ActiveEraser === InkEraserTool.Radius && this._showEraserCircle && (
- <div
- onPointerMove={this.onCursorMove}
- style={{
- position: 'fixed',
- left: this._eraserX,
- top: this._eraserY,
- width: (ActiveEraserWidth() + 5) * 2,
- height: (ActiveEraserWidth() + 5) * 2,
- borderRadius: '50%',
- border: '1px solid gray',
- transform: 'translate(-50%, -50%)',
+ <div className="imageBox-aiView-history">
+ {/* {this._prevImgs.map(img => (
+ <img
+ className="imageBox-aiView-img"
+ src={img.href}
+ onClick={() => {
+ this.dataDoc[this.fieldKey] = new ImageField(img.pathname);
+ this.dataDoc.ai_firefly_prompt = img.prompt;
+ this.dataDoc.ai_firefly_seed = img.seed;
}}
/>
- )}
- {this.paintFunc ? (
- <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads
- ) : this._lightboxDoc ? (
- <div style={{ padding: 15, width: '100%', height: '100%' }}>
- <DocumentView
- {...this._props}
- Document={this._lightboxDoc}
- containerViewPath={this.DocumentView?.().docViewPath}
- TemplateDataDocument={undefined}
- PanelWidth={this.lightboxPanelWidth}
- PanelHeight={this.lightboxPanelHeight}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- onClickScript={this.onChildClickHandler}
- onKey={this.onKeyDown}
- onDoubleClickScript={this.onChildDoubleClickHandler}
- childFilters={this.childDocFilters}
- childFiltersByRanges={this.childDocRangeFilters}
- searchFilterDocs={this.searchFilterDocs}
- isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this.isContentActive}
- isContentActive={this._props.childContentsActive ?? emptyFunction}
- addDocTab={this.addDocTab}
- ScreenToLocalTransform={this.lightboxScreenToLocal}
- fitContentsToBox={undefined}
- focus={this.focus}
- />
+ ))} */}
+ </div>
+ );
+ };
+
+ componentAIView = () => {
+ const showRegenerate = this.Document[DocData].ai;
+ return (
+ <div className="collectionfreeformview-aiView">
+ Edit Image with AI
+ {showRegenerate && (
+ <div className="collectionfreeformview-aiView-regenerate-container">
+ {/* <text className="collectionfreeformview-aiView-subtitle">Regenerate AI Image</text>
+ <div className="collectionfreeformview-aiView-regenerate">
+ <input
+ className="collectionfreeformview-aiView-input"
+ aria-label="Edit instructions input"
+ // className="smartdraw-input"
+ type="text"
+ value={this._regenInput}
+ onChange={action(e => this._canInteract && (this._regenInput = e.target.value))}
+ // onKeyDown={this.handleKeyPress}
+ placeholder="Prompt (Optional)"
+ />
+ <Button
+ text="Regenerate"
+ type={Type.SEC}
+ icon={this._regenerateLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
+ iconPlacement="right"
+ onClick={action(async () => {
+ this._regenerateLoading = true;
+ SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true).then(newDrawings => {
+ if (newDrawings[0]) {
+ }
+ });
+ })}
+ />
+ <Button
+ // style={{ alignSelf: 'flex-end' }}
+ text="Get Variations"
+ type={Type.SEC}
+ // icon={this._isLoading && this._regenInput !== '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
+ iconPlacement="right"
+ // onClick={this.handleSendClick}
+ />
+ </div> */}
</div>
- ) : (
- <>
- {this._firstRender ? this.placeholder : this.marqueeView}
- {this._props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
- {!this.GroupChildDrag ? null : <div className="collectionFreeForm-groupDropper" />}
- </>
)}
+ <div className="collectionfreeformview-aiView-options-container">
+ {showRegenerate && <text className="collectionfreeformview-aiView-subtitle"> Turn Drawing to Image </text>}
+ <div className="collectionfreeformview-aiView-options"></div>
+ </div>
+ </div>
+ );
+ };
+
+ render() {
+ TraceMobx();
+ return (
+ <div>
+ <div
+ className="collectionfreeformview-container"
+ id={this._paintedId}
+ ref={r => {
+ this.createDashEventsTarget(r);
+ this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+ this._oldWheel = r;
+ // prevent wheel events from passivly propagating up through containers
+ r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ r?.addEventListener('mouseleave', this.onMouseLeave);
+ r?.addEventListener('mouseenter', this.onMouseEnter);
+ }}
+ onWheel={this.onPointerWheel}
+ onClick={this.onClick}
+ onPointerDown={this.onPointerDown}
+ onPointerMove={this.onCursorMove}
+ onDrop={this.onExternalDrop}
+ onDragOver={e => e.preventDefault()}
+ onContextMenu={this.onContextMenu}
+ style={{
+ pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : this._props.pointerEvents?.(),
+ textAlign: this.isAnnotationOverlay ? 'initial' : undefined,
+ transform: `scale(${this.nativeDimScaling})`,
+ width: `${100 / this.nativeDimScaling}%`,
+ height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`,
+ }}>
+ {Doc.ActiveTool === InkTool.Eraser && Doc.ActiveEraser === InkEraserTool.Radius && this._showEraserCircle && (
+ <div
+ onPointerMove={this.onCursorMove}
+ style={{
+ position: 'fixed',
+ left: this._eraserX,
+ top: this._eraserY,
+ width: (ActiveEraserWidth() + 5) * 2,
+ height: (ActiveEraserWidth() + 5) * 2,
+ borderRadius: '50%',
+ border: '1px solid gray',
+ transform: 'translate(-50%, -50%)',
+ }}
+ />
+ )}
+ {this.paintFunc ? (
+ <FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads
+ ) : this._lightboxDoc ? (
+ <div style={{ padding: 15, width: '100%', height: '100%' }}>
+ <DocumentView
+ {...this._props}
+ Document={this._lightboxDoc}
+ containerViewPath={this.DocumentView?.().docViewPath}
+ TemplateDataDocument={undefined}
+ PanelWidth={this.lightboxPanelWidth}
+ PanelHeight={this.lightboxPanelHeight}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ onClickScript={this.onChildClickHandler}
+ onKey={this.onKeyDown}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ childFilters={this.childDocFilters}
+ childFiltersByRanges={this.childDocRangeFilters}
+ searchFilterDocs={this.searchFilterDocs}
+ isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this.isContentActive}
+ isContentActive={this._props.childContentsActive ?? emptyFunction}
+ addDocTab={this.addDocTab}
+ ScreenToLocalTransform={this.lightboxScreenToLocal}
+ fitContentsToBox={undefined}
+ focus={this.focus}
+ />
+ </div>
+ ) : (
+ <>
+ {this._firstRender ? this.placeholder : this.marqueeView}
+ {this._props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
+ {!this.GroupChildDrag ? null : <div className="collectionFreeForm-groupDropper" />}
+ </>
+ )}
+ </div>
</div>
);
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a1fa9a283..6b9e170c8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -580,24 +580,21 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// style={{ alignSelf: 'flex-end' }}
icon={this._regenerateLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
iconPlacement="right"
- onClick={undoable(
- action(async () => {
- this._regenerateLoading = true;
- SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true).then(newImgs => {
- if (newImgs[0]) {
- const url = newImgs[0].pathname;
- const imgField = new ImageField(url);
- this._prevImgs.length === 0 &&
- this._prevImgs.push({ prompt: StrCast(this.dataDoc.ai_firefly_prompt), seed: NumCast(this.dataDoc.ai_firefly_seed), href: this.paths.lastElement(), pathname: field.url.pathname });
- this.dataDoc[this.fieldKey] = imgField;
- this._prevImgs.unshift({ prompt: newImgs[0].prompt, seed: newImgs[0].seed, href: this.paths.lastElement(), pathname: url });
- this._regenerateLoading = false;
- this._regenInput = '';
- }
- });
- }),
- 'regenerate image'
- )}
+ onClick={action(async () => {
+ this._regenerateLoading = true;
+ SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true).then(newImgs => {
+ if (newImgs[0]) {
+ const url = newImgs[0].pathname;
+ const imgField = new ImageField(url);
+ this._prevImgs.length === 0 &&
+ this._prevImgs.push({ prompt: StrCast(this.dataDoc.ai_firefly_prompt), seed: this.dataDoc.ai_firefly_seed as number, href: this.paths.lastElement(), pathname: field.url.pathname });
+ this.dataDoc[this.fieldKey] = imgField;
+ this._prevImgs.unshift({ prompt: newImgs[0].prompt, seed: newImgs[0].seed, href: this.paths.lastElement(), pathname: url });
+ this._regenerateLoading = false;
+ this._regenInput = '';
+ }
+ });
+ })}
/>
<Button
// style={{ alignSelf: 'flex-end' }}
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 5ebe2e358..af5fd727f 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -271,8 +271,8 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
this._lastInput.text = input;
const dims = FireflyDimensionsMap[this._imgDims];
return Networking.PostToServer('/queryFireflyImage', { prompt: input, width: dims.width, height: dims.height, seed: seed }).then(img => {
+ const seed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)[1];
if (!changeInPlace) {
- const seed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)[1];
const imgDoc: Doc = Docs.Create.ImageDocument(img.accessPaths.agnostic.client, {
title: input.match(/^(.*?)~~~.*$/)?.[1] || input,
nativeWidth: dims.width,