diff options
author | sharkiecodes <lanyi_stroud@brown.edu> | 2025-06-06 11:07:59 -0400 |
---|---|---|
committer | sharkiecodes <lanyi_stroud@brown.edu> | 2025-06-06 11:07:59 -0400 |
commit | 08b40f21d9295f36277827ac33085f82c9ee1646 (patch) | |
tree | a3fa109edc300200981e1015bfc1ca023fb477f1 | |
parent | e7f17e49612ca514fa5b3919f2c7459dcad448f7 (diff) |
clean-up
10 files changed, 114 insertions, 404 deletions
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b8d203cf6..9f96163cd 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -16,7 +16,7 @@ import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs, DocumentOptions } from '../../../documents/Documents'; import { SnappingManager, freeformScrollMode } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { UndoManager, undoBatch } from '../../../util/UndoManager'; +import { UndoManager, undoBatch, undoable } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { MarqueeViewBounds } from '../../PinFuncs'; @@ -548,7 +548,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps })); } - + generateScrapbook = action(async () => { const selectedDocs = this.marqueeSelect(false); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 2473f1c0a..79a218e45 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -46,7 +46,6 @@ import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; import { gptImageLabel } from '../../apis/gpt/GPT'; -import { ImageLabelBox } from '../collections/collectionFreeForm/ImageLabelBox'; const DefaultPath = '/assets/unknown-file-icon-hi.png'; export class ImageEditorData { @@ -157,13 +156,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this.Document.$tags_chat = new List<string>(); tokens.forEach(tok => { (this.Document.$tags_chat as List<string>).push(tok)}); - (this.Document.$tags_chat as List<string>).push(`ASPECT_${aspectRatio}`); - //!!! changed may 11 (this.Document.$tags_chat as List<string>).push(label); + (this.Document.$tags_chat as List<string>).push(`ASPECT_${aspectRatio}`); // 6) flip on “show tags” in the layout // (same flag that ImageLabelBox.toggleDisplayInformation uses) - //note to self: What if i used my own field (ex: Document.$auto_description or something - //Would i still have to toggle it on for it to show in the metadata? this.Document._layout_showTags = true; } catch (err) { @@ -172,8 +168,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } }; - //Doc.getDescription(this.Document).then(desc => this.desc = desc) - diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 04a14a15f..ad75d320a 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -329,29 +329,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB this.Document._layout_showTags = true; }); }); - /*this.Document.$tags_chat = new List<string>(); - gptAPICall(RTFCast(this.Document[Doc.LayoutDataKey(this.Document)])?.Text ?? StrCast(this.Document[Doc.LayoutDataKey(this.Document)]), GPTCallType.CLASSIFYTEXTMINIMAL).then(desc => (this.Document.$tags_chat as List<string>).push(desc)); - this.Document._layout_showTags = true;*/ - - - // 2) grab whatever’s actually in the field (either RTF or plain string) -/* - const rawText = RTFCast(this.Document[Doc.LayoutDataKey(this.Document)])?.Text ?? StrCast(this.Document[Doc.LayoutDataKey(this.Document)]) - - // 3) pick minimal vs. full classification based on "[placeholder]" substring - if (rawText.includes("[placeholder]")) { - this.Document.$tags_chat = new List<string>(); - gptAPICall(RTFCast(this.Document[Doc.LayoutDataKey(this.Document)])?.Text ?? StrCast(this.Document[Doc.LayoutDataKey(this.Document)]), GPTCallType.CLASSIFYTEXTMINIMAL).then(desc => { - (this.Document.$tags_chat as List<string>).push(desc); - }); - } else { - this.Document.$tags_chat = new List<string>(); - gptAPICall(RTFCast(this.Document[Doc.LayoutDataKey(this.Document)])?.Text ?? StrCast(this.Document[Doc.LayoutDataKey(this.Document)]), GPTCallType.CLASSIFYTEXTFULL).then(desc => { - (this.Document.$tags_chat as List<string>).push(desc); - })}; - // 4) make sure the UI will show tags - this.Document._layout_showTags = true;*/ - }; leafText = (node: Node) => { diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.scss b/src/client/views/nodes/scrapbook/ScrapbookBox.scss new file mode 100644 index 000000000..8dc93df60 --- /dev/null +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.scss @@ -0,0 +1,63 @@ + +.scrapbook-box { + /* Make sure the container fills its parent, and set a base background */ + position: relative; /* so that absolute children (loading overlay, etc.) are positioned relative to this */ + width: 100%; + height: 100%; + background: beige; + overflow: hidden; /* prevent scrollbars if children overflow */ +} + +/* Loading overlay that covers the entire scrapbook while AI-generation is in progress */ +.scrapbook-box-loading-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background: rgba(255, 255, 255, 0.8); + z-index: 10; /* sits above the ImageBox and other content */ +} + +/* The <select> dropdown for choosing presets */ +.scrapbook-box-preset-select { + position: absolute; + top: 8px; + left: 8px; + z-index: 20; + padding: 4px 8px; + font-size: 14px; + border: 1px solid #ccc; + border-radius: 4px; + background: white; +} + +/* Container for the “Regenerate Background” button */ +.scrapbook-box-ui { + position: absolute; + top: 8px; + right: 8px; + z-index: 20; +} + +/* The button itself */ +.scrapbook-box-ui-button { + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + font-size: 14px; + color: black; + background: white; + border: 1px solid #ccc; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; +} + +.scrapbook-box-ui-button:hover { + background: #f5f5f5; +} diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx index eb997024b..e910f2fa7 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx @@ -27,6 +27,7 @@ import { runInAction } from 'mobx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faRedoAlt } from '@fortawesome/free-solid-svg-icons'; import { getPresetNames, createPreset } from './ScrapbookPresetRegistry'; +import './ScrapbookBox.scss'; export function buildPlaceholdersFromConfigs(configs: ScrapbookItemConfig[]): Doc[] { @@ -294,30 +295,6 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() } } - async generateAiImage() { - this.setState({ loading: true }); - - const prompt = 'A serene mountain landscape at sunrise, ultra-wide, pastel sky, abstract, scrapbook background'; - //'A serene mountain landscape at sunrise, ultra-wide, pastel sky'; - const dimensions = FireflyImageDimensions.Square; // or whichever suits your scenario - - SmartDrawHandler.CreateWithFirefly(prompt, dimensions) - .then(action(doc => { - if (doc instanceof Doc) { - const imgField = ImageCast(doc.data); - this.setState({ src: imgField?.url.href }); - } else { - alert('Failed to generate the image.'); - } - })) - .catch(e => { - alert(`Image generation error: ${e}`); - }) - .finally(() => { - this.setState({ loading: false }); - }); - } - componentDidMount() { //this.initScrapbook(ScrapbookPresetType.Default); this.setTitle(); @@ -346,38 +323,9 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() ;(this.imageBoxRef.current as any).layoutDoc._width = dims.w ;(this.imageBoxRef.current as any).layoutDoc._height = dims.h - // tell the imageDoc to resize itself to the *new* scrapbook size - //this.imgDoc._width = dims.w; - //this.imgDoc._height = dims.h; - //Doc.SetNativeWidth(this.imgDoc, dims.w); - //Doc.SetNativeHeight(this.imgDoc, dims.h); }); } ); - /* - this._disposers.propagateResize = reaction( - () => ({ w: this.layoutDoc._width, h: this.layoutDoc._height }), - ({ w, h }, prev) => { - // only when shift is held (i.e. outpaint mode) - if (SnappingManager.ShiftKey && this.imgDoc) { - const key = this.imageBoxRef.current!.props.fieldKey; // “data” - // record original size on the *image* doc: - this.imgDoc[key + '_outpaintOriginalWidth'] = this.imgDoc._width; - this.imgDoc[key + '_outpaintOriginalHeight'] = this.imgDoc._height; - } - } - );*/ - - - // this._disposers.outpaint = reaction( - // () => this.imgDoc?.[this.imgDoc.fieldKey + '_outpaintOriginalWidth'], - // originalWidth => { - // if (originalWidth !== undefined && !SnappingManager.ShiftKey) { - // this.imageBoxRef.current?.openOutpaintPrompt(); // ✅ CORRECT! - // } - // } - // ); - } @@ -462,9 +410,6 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }; - - - @computed get regenPrompt() { const slots = DocListCast(this.dataDoc[this.fieldKey]); @@ -495,129 +440,62 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() : 'A serene mountain landscape at sunrise, ultra-wide, pastel sky, abstract, scrapbook background'; } - render() { - - /*const internalTags = DocListCast(this.dataDoc[this.fieldKey]) - .flatMap(ph => StrListCast(ph.$tags_chat)) - .join(' ');*/ - - - return ( - <div style={{ background: 'beige', width: '100%', height: '100%' }}> - {this.loading && ( - <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', - display: 'flex', justifyContent: 'center', alignItems: 'center', - background: 'rgba(255,255,255,0.8)' }}> + render() { + return ( + <div className="scrapbook-box"> + {this.loading && ( + <div className="scrapbook-box-loading-overlay"> <ReactLoading type="spin" width={50} height={50} /> </div> )} - {this.loading && ( - <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', - display: 'flex', justifyContent: 'center', alignItems: 'center', - background: 'rgba(255,255,255,0.8)', zIndex: 10 }}> - <ReactLoading type="spin" width={50} height={50} /> - </div> - )} - {/* Render AI-generated background */} - {this.src && this.imgDoc && ( - <ImageBox - ref={this.imageBoxRef} - {...this._props} - Document={this.imgDoc} - fieldKey="data" - />)} - - - <select - value={this.selectedPreset} - onChange={e => (this.selectedPreset = e.currentTarget.value)} - style={{ position: 'absolute', top: 8, left: 8, zIndex: 20 }} + + {this.src && this.imgDoc && ( + <ImageBox + ref={this.imageBoxRef} + {...this._props} + Document={this.imgDoc} + fieldKey="data" + /> + )} + + <select + className="scrapbook-box-preset-select" + value={this.selectedPreset} + onChange={e => (this.selectedPreset = e.currentTarget.value)} > - {getPresetNames().map(name => ( - <option key={name} value={name}>{name}</option> - ))} - </select> + {getPresetNames().map(name => ( + <option key={name} value={name}> + {name} + </option> + ))} + </select> + {this._props.isContentActive() && ( - <div - className="scrapbookBox-ui" - style={{ - position: 'absolute', - top: 8, - right: 8, - zIndex: 20, - }} - onPointerDown={e => e.stopPropagation()} - > + <div className="scrapbook-box-ui"> <button - type="button" - title="Regenerate Background" - onClick={() => this.generateAiImageCorrect(this.regenPrompt)} - style={{ - color: 'black', - background: 'white', - border: '1px solid #ccc', - borderRadius: 4, - padding: '4px 8px', - cursor: 'pointer', - display: 'flex', - alignItems: 'center', - gap: '6px', - whiteSpace: 'nowrap', - overflow: 'visible', // important - fontSize: '14px', - }} + type="button" + title="Regenerate Background" + onClick={() => this.generateAiImageCorrect(this.regenPrompt)} + className="scrapbook-box-ui-button" > - <FontAwesomeIcon icon={faRedoAlt} /> - <span>Regenerate Background</span> + <FontAwesomeIcon icon={faRedoAlt} /> + <span>Regenerate Background</span> </button> - </div> - )} - - <CollectionView - {...this._props} // - setContentViewBox={emptyFunction} - rejectDrop={this.rejectDrop} - childRejectDrop={this.childRejectDrop} - filterAddDocument={this.filterAddDocument} - /> - {/* <div style={{ border: '1px black', borderStyle: 'dotted', position: 'absolute', top: '50%', width: '100%', textAlign: 'center' }}>Drop an image here</div> */} - </div> - ); - } -} - - - -//function extractScrapbookConfigs(docs: Doc[]): ScrapbookItemConfig[] { - //return docs.map(doc => extractConfig(doc)); -//} - -// function extractConfig(doc: Doc): ScrapbookItemConfig { -// const layoutKey = Doc.LayoutDataKey(doc); -// const childDocs = doc[layoutKey] ? DocListCast(doc[layoutKey]) : []; - -// const isContainer = childDocs.length > 0; - -// const cfg: ScrapbookItemConfig = { -// type: isContainer ? DocumentType.COL : doc.$type, -// tag: -// acceptTag: doc.accepts_tagType, -// x: doc.x || 0, -// y: doc.y || 0, -// width: doc._width, -// height: doc._height, -// }; - -// if (isContainer) { -// cfg.containerWidth = doc.proto._width; -// cfg.containerHeight = doc.proto._height; -// cfg.children = childDocs.map(child => extractConfig(child)); -// } + </div> + )} -// return cfg; -// } + <CollectionView + {...this._props} + setContentViewBox={emptyFunction} + rejectDrop={this.rejectDrop} + childRejectDrop={this.childRejectDrop} + filterAddDocument={this.filterAddDocument} + /> + </div> + ); + } +} -// Register scrapbook Docs.Prototypes.TemplateMap.set(DocumentType.SCRAPBOOK, { diff --git a/src/client/views/nodes/scrapbook/ScrapbookSettingsPanel.tsx b/src/client/views/nodes/scrapbook/ScrapbookSettingsPanel.tsx deleted file mode 100644 index 5808ab4d1..000000000 --- a/src/client/views/nodes/scrapbook/ScrapbookSettingsPanel.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faRedoAlt } from '@fortawesome/free-solid-svg-icons'; -import { action } from 'mobx'; - -export default class ScrapbookSettingsPanel extends React.Component { - - constructor(props) { - super(props); - this.state = { regenerating: false }; - } - - regenerateScrapbook = async () => { - this.setState({ regenerating: true }); - try { - // Example API call or method invoking ChatGPT for JSON - const newLayout = await fetch('/api/generate-scrapbook-layout', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ currentLayout: this.props.currentLayout }) - }).then(res => res.json()); - - action(() => { - // Apply new layout - this.props.applyNewLayout(newLayout); - })(); - } catch (err) { - console.error('Failed to regenerate layout:', err); - } finally { - this.setState({ regenerating: false }); - } - }; - - render() { - const { regenerating } = this.state; - - return ( - <div className="scrapbook-settings-panel" style={{ display: 'flex', alignItems: 'center', padding: '8px', backgroundColor: '#f0f0f0', borderRadius: '8px', boxShadow: '0 4px 8px rgba(0,0,0,0.1)' }}> - <button - className="regenerate-scrapbook-btn" - title="Regenerate Scrapbook" - onClick={this.regenerateScrapbook} - disabled={regenerating} - style={{ - padding: '8px 12px', - background: regenerating ? '#ccc' : '#007bff', - color: 'white', - border: 'none', - borderRadius: '4px', - cursor: regenerating ? 'default' : 'pointer', - display: 'flex', - alignItems: 'center' - }}> - <FontAwesomeIcon icon={faRedoAlt} style={{ marginRight: '6px' }} /> - {regenerating ? 'Regenerating...' : 'Regenerate Scrapbook'} - </button> - </div> - ); - } -}
\ No newline at end of file diff --git a/src/client/views/nodes/scrapbook/ScrapbookSlot.scss b/src/client/views/nodes/scrapbook/ScrapbookSlot.scss deleted file mode 100644 index ae647ad36..000000000 --- a/src/client/views/nodes/scrapbook/ScrapbookSlot.scss +++ /dev/null @@ -1,85 +0,0 @@ -//IGNORE FOR NOW, CURRENTLY NOT USED IN SCRAPBOOK IMPLEMENTATION -.scrapbook-slot { - position: absolute; - background-color: rgba(245, 245, 245, 0.7); - border: 2px dashed #ccc; - border-radius: 5px; - box-sizing: border-box; - transition: all 0.2s ease; - overflow: hidden; - - &.scrapbook-slot-over { - border-color: #4a90e2; - background-color: rgba(74, 144, 226, 0.1); - } - - &.scrapbook-slot-filled { - border-style: solid; - border-color: rgba(0, 0, 0, 0.1); - background-color: transparent; - - &.scrapbook-slot-over { - border-color: #4a90e2; - background-color: rgba(74, 144, 226, 0.1); - } - } - - .scrapbook-slot-empty { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - } - - .scrapbook-slot-placeholder { - text-align: center; - color: #888; - } - - .scrapbook-slot-title { - font-weight: bold; - margin-bottom: 5px; - } - - .scrapbook-slot-instruction { - font-size: 0.9em; - font-style: italic; - } - - .scrapbook-slot-content { - width: 100%; - height: 100%; - position: relative; - } - - .scrapbook-slot-controls { - position: absolute; - top: 5px; - right: 5px; - z-index: 10; - opacity: 0; - transition: opacity 0.2s ease; - - .scrapbook-slot-remove-btn { - background-color: rgba(255, 255, 255, 0.8); - border: 1px solid #ccc; - border-radius: 50%; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - font-size: 10px; - - &:hover { - background-color: rgba(255, 0, 0, 0.1); - } - } - } - - &:hover .scrapbook-slot-controls { - opacity: 1; - } -}
\ No newline at end of file diff --git a/src/client/views/nodes/scrapbook/ScrapbookSlot.tsx b/src/client/views/nodes/scrapbook/ScrapbookSlot.tsx deleted file mode 100644 index 2c8f93778..000000000 --- a/src/client/views/nodes/scrapbook/ScrapbookSlot.tsx +++ /dev/null @@ -1,28 +0,0 @@ - -//IGNORE FOR NOW, CURRENTLY NOT USED IN SCRAPBOOK IMPLEMENTATION -export interface SlotDefinition { - id: string; - x: number; y: number; - defaultWidth: number; - defaultHeight: number; - } - - export interface SlotContentMap { - slotId: string; - docId?: string; - } - - export interface ScrapbookConfig { - slots: SlotDefinition[]; - contents?: SlotContentMap[]; - } - - export const DEFAULT_SCRAPBOOK_CONFIG: ScrapbookConfig = { - slots: [ - { id: "slot1", x: 10, y: 10, defaultWidth: 180, defaultHeight: 120 }, - { id: "slot2", x: 200, y: 10, defaultWidth: 180, defaultHeight: 120 }, - // …etc - ], - contents: [] - }; -
\ No newline at end of file diff --git a/src/client/views/nodes/scrapbook/ScrapbookSlotTypes.ts b/src/client/views/nodes/scrapbook/ScrapbookSlotTypes.ts deleted file mode 100644 index 686917d9a..000000000 --- a/src/client/views/nodes/scrapbook/ScrapbookSlotTypes.ts +++ /dev/null @@ -1,25 +0,0 @@ -// ScrapbookSlotTypes.ts -export interface SlotDefinition { - id: string; - title: string; - x: number; - y: number; - defaultWidth: number; - defaultHeight: number; - } - - export interface ScrapbookConfig { - slots: SlotDefinition[]; - contents?: { slotId: string; docId: string }[]; - } - - // give it three slots by default: - export const DEFAULT_SCRAPBOOK_CONFIG: ScrapbookConfig = { - slots: [ - { id: "main", title: "Main Content", x: 20, y: 20, defaultWidth: 360, defaultHeight: 200 }, - { id: "notes", title: "Notes", x: 20, y: 240, defaultWidth: 360, defaultHeight: 160 }, - { id: "resources", title: "Resources", x: 400, y: 20, defaultWidth: 320, defaultHeight: 380 }, - ], - contents: [], - }; -
\ No newline at end of file diff --git a/src/client/views/nodes/scrapbook/scrapbookleftover.ts b/src/client/views/nodes/scrapbook/scrapbookleftover.ts index 2f381ab95..ee7a858e4 100644 --- a/src/client/views/nodes/scrapbook/scrapbookleftover.ts +++ b/src/client/views/nodes/scrapbook/scrapbookleftover.ts @@ -1,8 +1,4 @@ - - - - - //DocListCast(this.Document.items).map(doc => DocListCast(doc[Doc.LayoutDataKey(doc)]) + //DocListCast(this.Document.items).map(doc => DocListCast(doc[Doc.LayoutDataKey(doc)]) if (placeholder) { /**Look at the autotags and see what matches*RTFCast(d[Doc.LayoutDataKey(d)])?.Text*/ |