From 45e22be891331e2d6a381e988c7abd29af3e1399 Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Wed, 8 Jan 2025 02:26:53 -0500
Subject: added componentAIView for collections

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 226 ++++++++++++++-------
 1 file changed, 152 insertions(+), 74 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

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>
         );
     }
-- 
cgit v1.2.3-70-g09d2

