From 403dcfb5e8b659f62ed51212ede3f5807caa58c6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 10 Jun 2025 19:06:31 -0400 Subject: cleanup and streamlining of scrapbook code. --- .../views/nodes/formattedText/FormattedTextBox.tsx | 44 +- src/client/views/nodes/scrapbook/ScrapbookBox.scss | 87 +-- src/client/views/nodes/scrapbook/ScrapbookBox.tsx | 645 +++++++-------------- .../views/nodes/scrapbook/ScrapbookPreset.tsx | 169 ++---- .../nodes/scrapbook/ScrapbookPresetRegistry.ts | 20 +- 5 files changed, 303 insertions(+), 662 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 0c3179173..1768eb08d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -8,7 +8,6 @@ import { baseKeymap, selectAll, splitBlock } from 'prosemirror-commands'; import { history } from 'prosemirror-history'; import { inputRules } from 'prosemirror-inputrules'; import { keymap } from 'prosemirror-keymap'; -import { runInAction } from 'mobx'; import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; import { EditorState, NodeSelection, Plugin, Selection, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView, NodeViewConstructor } from 'prosemirror-view'; @@ -65,7 +64,6 @@ import { removeMarkWithAttrs } from './prosemirrorPatches'; import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; -import { tickStep } from 'd3'; // import * as applyDevTools from 'prosemirror-dev-tools'; export interface FormattedTextBoxProps extends FieldViewProps { @@ -310,30 +308,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + autoTag = () => { + const rawText = RTFCast(this.Document[this.fieldKey])?.Text ?? StrCast(this.Document[this.fieldKey]); + const callType = rawText.includes('[placeholder]') ? GPTCallType.CLASSIFYTEXTMINIMAL : GPTCallType.CLASSIFYTEXTFULL; - const layoutKey = Doc.LayoutDataKey(this.Document); - const rawText = RTFCast(this.Document[layoutKey])?.Text ?? StrCast(this.Document[layoutKey]); - - const callType = rawText.includes("[placeholder]") - ? GPTCallType.CLASSIFYTEXTMINIMAL - : GPTCallType.CLASSIFYTEXTFULL; - - gptAPICall(rawText, callType).then(desc => { - runInAction(() => { - // Clear existing tags - this.Document.$tags_chat = new List(); - - // Split GPT response into tokens and push individually - const tokens = desc.trim().split(/\s+/); - tokens.forEach(tok => { - (this.Document.$tags_chat as List).push(tok); - }); - - this.Document._layout_showTags = true; - }); - }); -}; + gptAPICall(rawText, callType).then( + action(desc => { + // Split GPT response into tokens and push individually & clear existing tags + this.Document.$tags_chat = new List(desc.trim().split(/\s+/)); + this.Document._layout_showTags = true; + }) + ); + }; leafText = (node: Node) => { if (node.type === this.EditorView?.state.schema.nodes.dashField) { @@ -1298,13 +1284,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ({ title: this.Document.title, sel: this._props.isSelected() }), - action(() => { - this.autoTag(); - }), - { fireImmediately: true } - ); + this._disposers.tagger = reaction(() => ({ title: this.Document.title, sel: this._props.isSelected() }), this.autoTag, { fireImmediately: true }); if (!this._props.dontRegisterView) { this._disposers.record = reaction( diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.scss b/src/client/views/nodes/scrapbook/ScrapbookBox.scss index 8dc93df60..6ac2220f9 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookBox.scss +++ b/src/client/views/nodes/scrapbook/ScrapbookBox.scss @@ -1,63 +1,66 @@ - .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 */ + /* 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 */ + 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 (this.selectedPreset = e.currentTarget.value)} - > - {getPresetNames().map(name => ( - - ))} - - {this._props.isContentActive() && ( -
- -
- )} + return internalTags ? `Create a new scrapbook background featuring: ${internalTags}` : 'A serene mountain landscape at sunrise, ultra-wide, pastel sky, abstract, scrapbook background'; + } - - - ); - } + render() { + return ( +
+
+ +
+ + {this.BackgroundDoc && } +
+ +
+ } onClick={() => !this._loading && this.generateAiImage(this.regenPrompt)} /> +
+
+ + +
+ ); + } } - - Docs.Prototypes.TemplateMap.set(DocumentType.SCRAPBOOK, { layout: { view: ScrapbookBox, dataField: 'items' }, options: { diff --git a/src/client/views/nodes/scrapbook/ScrapbookPreset.tsx b/src/client/views/nodes/scrapbook/ScrapbookPreset.tsx index 706b9dafd..fe33741af 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookPreset.tsx +++ b/src/client/views/nodes/scrapbook/ScrapbookPreset.tsx @@ -1,23 +1,22 @@ import { DocumentType } from '../../../documents/DocumentTypes'; export enum ScrapbookPresetType { - Default = 'Default', - Classic = 'Classic', + Default = 'Default', + Classic = 'Classic', None = 'Select Template', - Collage = 'Collage', + Collage = 'Collage', Spotlight = 'Spotlight', - Gallery = 'Gallery' + Gallery = 'Gallery', } export interface ScrapbookItemConfig { - type: DocumentType; - /** text shown in the placeholder bubble */ - tag: string; - /** what this slot actually accepts (defaults to `tag`) */ - acceptTags?: string[]; - x: number; y: number; + + message?: string; // optional text to display instead of [placeholder] + acceptTags[0] + type?: DocumentType; + /** what this slot actually accepts (defaults to `tag`) */ + acceptTags?: string[]; /** the frame this placeholder occupies */ width?: number; height?: number; @@ -30,147 +29,65 @@ export interface ScrapbookItemConfig { export class ScrapbookPreset { static createPreset(presetType: ScrapbookPresetType): ScrapbookItemConfig[] { switch (presetType) { - case ScrapbookPresetType.None: - return ScrapbookPreset.createNonePreset(); - case ScrapbookPresetType.Classic: - return ScrapbookPreset.createClassicPreset(); - case ScrapbookPresetType.Collage: - return ScrapbookPreset.createCollagePreset(); - case ScrapbookPresetType.Spotlight: - return ScrapbookPreset.createSpotlightPreset(); - case ScrapbookPresetType.Default: - return ScrapbookPreset.createDefaultPreset(); - case ScrapbookPresetType.Gallery: - return ScrapbookPreset.createGalleryPreset(); + case ScrapbookPresetType.None: return ScrapbookPreset.createNonePreset(); + case ScrapbookPresetType.Classic: return ScrapbookPreset.createClassicPreset(); + case ScrapbookPresetType.Collage: return ScrapbookPreset.createCollagePreset(); + case ScrapbookPresetType.Spotlight: return ScrapbookPreset.createSpotlightPreset(); + case ScrapbookPresetType.Default: return ScrapbookPreset.createDefaultPreset(); + case ScrapbookPresetType.Gallery: return ScrapbookPreset.createGalleryPreset(); default: throw new Error(`Unknown preset type: ${presetType}`); - } + } // prettier-ignore } - private static createNonePreset(): ScrapbookItemConfig[] { - return [ - - { type: DocumentType.RTF, - tag: 'To create a scrapbook from existing documents, marquee select. For existing scrapbook arrangements, select a preset from the dropdown.', - acceptTags: ['n/a'], - x: 0, y: 0, width: 250, height: 200 - }, - - ]; + private static createNonePreset(): ScrapbookItemConfig[] { + return [{ message: 'To create a scrapbook from existing documents, marquee select. For existing scrapbook arrangements, select a preset from the dropdown.', type: DocumentType.RTF, acceptTags: [], x: 0, y: 0, width: 250, height: 200 }]; } private static createClassicPreset(): ScrapbookItemConfig[] { return [ - { type: DocumentType.IMG, - tag: '[placeholder] LANDSCAPE', - acceptTags: ['LANDSCAPE'], - x: 0, y: -100, width: 250, height: 200 - }, - { type: DocumentType.RTF, - tag: '[placeholder] caption', - acceptTags: ['sentence'], - x: 0, y: 200, width: 250, height: 50 - }, - { type: DocumentType.RTF, - tag: '[placeholder] lengthy description', - acceptTags: ['paragraphs'], - x: 280, y: -50, width: 50, height: 200 - }, - { type: DocumentType.IMG, - tag: '[placeholder] PERSON', - acceptTags: ['PERSON'], - x: -200, y: -100, width: 100, height: 200 - }, + { type: DocumentType.IMG, message: '[placeholder] LANDSCAPE', acceptTags: ['LANDSCAPE'], x: 0, y: -100, width: 250, height: 200 }, + { type: DocumentType.RTF, message: '[placeholder] caption', acceptTags: ['sentence'], x: 0, y: 200, width: 250, height: 50 }, + { type: DocumentType.RTF, message: '[placeholder] lengthy description', acceptTags: ['paragraphs'], x: 280, y: -50, width: 50, height: 200 }, + { type: DocumentType.IMG, message: '[placeholder] PERSON', acceptTags: ['PERSON'], x: -200, y: -100, width: 100, height: 200 }, ]; } private static createGalleryPreset(): ScrapbookItemConfig[] { return [ - { type: DocumentType.IMG, tag: 'Gallery 1', acceptTags: ['LANDSCAPE'], x: -150, y: -150, width: 150, height: 150 }, - { type: DocumentType.IMG, tag: 'Gallery 2', acceptTags: ['LANDSCAPE'], x: 0, y: -150, width: 150, height: 150 }, - { type: DocumentType.IMG, tag: 'Gallery 3', acceptTags: ['LANDSCAPE'], x: 150, y: -150, width: 150, height: 150 }, - { type: DocumentType.IMG, tag: 'Gallery 4', acceptTags: ['LANDSCAPE'], x: -150, y: 0, width: 150, height: 150 }, - { type: DocumentType.IMG, tag: 'Gallery 5', acceptTags: ['LANDSCAPE'], x: 0, y: 0, width: 150, height: 150 }, - { type: DocumentType.IMG, tag: 'Gallery 6', acceptTags: ['LANDSCAPE'], x: 150, y: 0, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 1', acceptTags: ['LANDSCAPE'], x: -150, y: -150, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 2', acceptTags: ['LANDSCAPE'], x: 0, y: -150, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 3', acceptTags: ['LANDSCAPE'], x: 150, y: -150, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 4', acceptTags: ['LANDSCAPE'], x: -150, y: 0, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 5', acceptTags: ['LANDSCAPE'], x: 0, y: 0, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'Gallery 6', acceptTags: ['LANDSCAPE'], x: 150, y: 0, width: 150, height: 150 }, ]; - } - + } private static createDefaultPreset(): ScrapbookItemConfig[] { return [ - { type: DocumentType.IMG, - tag: 'image', - acceptTags: ['LANDSCAPE'], - x: 0, y: -100, width: 250, height: 200 - }, - { type: DocumentType.RTF, - tag: 'summary', - acceptTags: ['sentence'], - x: 0, y: 200, width: 250 - }, - { type: DocumentType.RTF, - tag: 'sidebar', - acceptTags: ['paragraphs'], - x: 280, y: -50, width: 50, height: 200 - }, - { - type: DocumentType.COL, - tag: 'internal coll', - x: -200, y: -100, width: 100, height: 200, - containerWidth: 300, containerHeight: 300, - children: [ - { type: DocumentType.IMG, - tag: 'image internal', - acceptTags: ['PERSON'], - x: 0, y: 0, width: 50, height: 100 - } - ] - } - ]; + { type: DocumentType.IMG, message: 'image', acceptTags: ['LANDSCAPE'], x: 0, y: -100, width: 250, height: 200 }, + { type: DocumentType.RTF, message: 'summary', acceptTags: ['sentence'], x: 0, y: 200, width: 250 }, + { type: DocumentType.RTF, message: 'sidebar', acceptTags: ['paragraphs'], x: 280, y: -50, width: 50, height: 200 }, + { containerWidth: 300, containerHeight: 300, x: -200, y: -100, width: 100, height: 200, + children: [{ type: DocumentType.IMG, message: 'image internal', acceptTags: ['PERSON'], x: 0, y: 0, width: 50, height: 100 }], }, + ]; // prettier-ignore } private static createCollagePreset(): ScrapbookItemConfig[] { return [ - { type: DocumentType.IMG, - tag: 'LANDSCAPE', - acceptTags: ['LANDSCAPE'], - x: -150, y: -150, width: 150, height: 150 - }, - { type: DocumentType.IMG, - tag: 'PERSON', - acceptTags: ['PERSON'], - x: 0, y: -150, width: 150, height: 150 - }, - { type: DocumentType.RTF, - tag: 'caption', - acceptTags: ['sentence'], - x: -150, y: 0, width: 300, height: 100 - }, - { type: DocumentType.RTF, - tag: 'lengthy description', - acceptTags: ['paragraphs'], - x: 0, y: 100, width: 300, height: 100 - } - ]; + { type: DocumentType.IMG, message: 'LANDSCAPE', acceptTags: ['LANDSCAPE'], x: -150, y: -150, width: 150, height: 150 }, + { type: DocumentType.IMG, message: 'PERSON', acceptTags: ['PERSON'], x: 0, y: -150, width: 150, height: 150 }, + { type: DocumentType.RTF, message: 'caption', acceptTags: ['sentence'], x: -150, y: 0, width: 300, height: 100 }, + { type: DocumentType.RTF, message: 'lengthy description', acceptTags: ['paragraphs'], x: 0, y: 100, width: 300, height: 100 }, + ]; // prettier-ignore } private static createSpotlightPreset(): ScrapbookItemConfig[] { return [ - { type: DocumentType.RTF, - tag: 'title', - acceptTags: ['word'], - x: 0, y: -180, width: 300, height: 40 - }, - { type: DocumentType.IMG, - tag: 'LANDSCAPE', - acceptTags: ['LANDSCAPE'], - x: 0, y: 0, width: 300, height: 200 - }, - { type: DocumentType.RTF, - tag: 'caption', - acceptTags: ['sentence'], - x: 0, y: 230, width: 300, height: 50 - } + { type: DocumentType.RTF, message: 'title', acceptTags: ['word'], x: 0, y: -180, width: 300, height: 40 }, + { type: DocumentType.IMG, message: 'LANDSCAPE', acceptTags: ['LANDSCAPE'], x: 0, y: 0, width: 300, height: 200 }, + { type: DocumentType.RTF, message: 'caption', acceptTags: ['sentence'], x: 0, y: 230, width: 300, height: 50 }, ]; } } diff --git a/src/client/views/nodes/scrapbook/ScrapbookPresetRegistry.ts b/src/client/views/nodes/scrapbook/ScrapbookPresetRegistry.ts index c6d67ab73..3a2189d00 100644 --- a/src/client/views/nodes/scrapbook/ScrapbookPresetRegistry.ts +++ b/src/client/views/nodes/scrapbook/ScrapbookPresetRegistry.ts @@ -6,39 +6,31 @@ type PresetGenerator = () => ScrapbookItemConfig[]; // Internal map of preset name to generator const presetRegistry = new Map(); - - - /** * Register a new scrapbook preset under the given name. */ export function registerPreset(name: string, gen: PresetGenerator) { - presetRegistry.set(name, gen); + presetRegistry.set(name, gen); } /** * List all registered preset names. */ export function getPresetNames(): string[] { - return Array.from(presetRegistry.keys()); + return Array.from(presetRegistry.keys()); } /** * Create the config array for the named preset. */ export function createPreset(name: string): ScrapbookItemConfig[] { - const gen = presetRegistry.get(name); - if (!gen) throw new Error(`Unknown scrapbook preset: ${name}`); - return gen(); + const gen = presetRegistry.get(name); + if (!gen) throw new Error(`Unknown scrapbook preset: ${name}`); + return gen(); } // ------------------------ // Register built-in presets import { ScrapbookPreset } from './ScrapbookPreset'; -registerPreset(ScrapbookPresetType.None, () => ScrapbookPreset.createPreset(ScrapbookPresetType.None)); -registerPreset(ScrapbookPresetType.Classic, () => ScrapbookPreset.createPreset(ScrapbookPresetType.Classic)); -registerPreset(ScrapbookPresetType.Collage, () => ScrapbookPreset.createPreset(ScrapbookPresetType.Collage)); -registerPreset(ScrapbookPresetType.Spotlight, () => ScrapbookPreset.createPreset(ScrapbookPresetType.Spotlight)); -registerPreset(ScrapbookPresetType.Default, () => ScrapbookPreset.createPreset(ScrapbookPresetType.Default)); -registerPreset(ScrapbookPresetType.Gallery, () => ScrapbookPreset.createPreset(ScrapbookPresetType.Gallery)); +Object.keys(ScrapbookPresetType).forEach(key => registerPreset(key, () => ScrapbookPreset.createPreset(key as ScrapbookPresetType))); // pretter-ignore -- cgit v1.2.3-70-g09d2