aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-04-30 14:43:29 -0400
committerbobzel <zzzman@gmail.com>2025-04-30 14:43:29 -0400
commit0317a667a5d4a0f298522eeddb8afa96e7b7ecfc (patch)
tree2d66c3caa5c102a3ca78837b87e61c16fd07fc01 /src/client/views/nodes/scrapbook/ScrapbookBox.tsx
parent9ec7df6af508eccdfda3a195a69c8bb1f86c41ea (diff)
parent2296c314be710f983d595de37c9d8039d73568a6 (diff)
Merge branch 'master' into task_nodes_aarav
Diffstat (limited to 'src/client/views/nodes/scrapbook/ScrapbookBox.tsx')
-rw-r--r--src/client/views/nodes/scrapbook/ScrapbookBox.tsx143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
new file mode 100644
index 000000000..6cfe9a62c
--- /dev/null
+++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
@@ -0,0 +1,143 @@
+import { action, makeObservable, observable } from 'mobx';
+import * as React from 'react';
+import { Doc, DocListCast } from '../../../../fields/Doc';
+import { List } from '../../../../fields/List';
+import { emptyFunction } from '../../../../Utils';
+import { Docs } from '../../../documents/Documents';
+import { DocumentType } from '../../../documents/DocumentTypes';
+import { CollectionView } from '../../collections/CollectionView';
+import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { DocumentView } from '../DocumentView';
+import { FieldView, FieldViewProps } from '../FieldView';
+import { DragManager } from '../../../util/DragManager';
+import { RTFCast, StrCast, toList } from '../../../../fields/Types';
+import { undoable } from '../../../util/UndoManager';
+// Scrapbook view: a container that lays out its child items in a grid/template
+export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+ @observable createdDate: string;
+
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ this.createdDate = this.getFormattedDate();
+
+ // ensure we always have a List<Doc> in dataDoc['items']
+ if (!this.dataDoc[this.fieldKey]) {
+ this.dataDoc[this.fieldKey] = new List<Doc>();
+ }
+ this.createdDate = this.getFormattedDate();
+ this.setTitle();
+ }
+
+ public static LayoutString(fieldStr: string) {
+ return FieldView.LayoutString(ScrapbookBox, fieldStr);
+ }
+
+ getFormattedDate(): string {
+ return new Date().toLocaleDateString(undefined, {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ });
+ }
+
+ @action
+ setTitle() {
+ const title = `Scrapbook - ${this.createdDate}`;
+ if (this.dataDoc.title !== title) {
+ this.dataDoc.title = title;
+
+ const image = Docs.Create.TextDocument('image');
+ image.accepts_docType = DocumentType.IMG;
+ const placeholder = new Doc();
+ placeholder.proto = image;
+ placeholder.original = image;
+ placeholder._width = 250;
+ placeholder._height = 200;
+ placeholder.x = 0;
+ placeholder.y = -100;
+ //placeholder.overrideFields = new List<string>(['x', 'y']); // shouldn't need to do this for layout fields since the placeholder already overrides its protos
+
+ const summary = Docs.Create.TextDocument('summary');
+ summary.accepts_docType = DocumentType.RTF;
+ summary.accepts_textType = 'one line';
+ const placeholder2 = new Doc();
+ placeholder2.proto = summary;
+ placeholder2.original = summary;
+ placeholder2.x = 0;
+ placeholder2.y = 200;
+ placeholder2._width = 250;
+ //placeholder2.overrideFields = new List<string>(['x', 'y', '_width']); // shouldn't need to do this for layout fields since the placeholder already overrides its protos
+ this.dataDoc[this.fieldKey] = new List<Doc>([placeholder, placeholder2]);
+ }
+ }
+
+ componentDidMount() {
+ this.setTitle();
+ }
+
+ childRejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => {
+ return true; // disable dropping documents onto any child of the scrapbook.
+ };
+ rejectDrop = (de: DragManager.DropEvent, subView?: DocumentView) => {
+ // Test to see if the dropped doc is dropped on an acceptable location (anywerhe? on a specific box).
+ // const draggedDocs = de.complete.docDragData?.draggedDocuments;
+ return false; // allow all Docs to be dropped onto scrapbook -- let filterAddDocument make the final decision.
+ };
+
+ filterAddDocument = (docIn: Doc | Doc[]) => {
+ const docs = toList(docIn);
+ if (docs?.length === 1) {
+ const placeholder = DocListCast(this.dataDoc[this.fieldKey]).find(d =>
+ (d.accepts_docType === docs[0].$type || // match fields based on type, or by analyzing content .. simple example of matching text in placeholder to dropped doc's type
+ RTFCast(d[Doc.LayoutDataKey(d)])?.Text.includes(StrCast(docs[0].$type)))
+ ); // prettier-ignore
+
+ if (placeholder) {
+ // ugh. we have to tell the underlying view not to add the Doc so that we can add it where we want it.
+ // However, returning 'false' triggers an undo. so this settimeout is needed to make the assignment happen after the undo.
+ setTimeout(
+ undoable(() => {
+ //StrListCast(placeholder.overrideFields).map(field => (docs[0][field] = placeholder[field])); // // shouldn't need to do this for layout fields since the placeholder already overrides its protos
+ placeholder.proto = docs[0];
+ }, 'Scrapbook add')
+ );
+ return false;
+ }
+ }
+ return false;
+ };
+
+ render() {
+ return (
+ <div style={{ background: 'beige', width: '100%', height: '100%' }}>
+ <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>
+ );
+ }
+}
+
+// Register scrapbook
+Docs.Prototypes.TemplateMap.set(DocumentType.SCRAPBOOK, {
+ layout: { view: ScrapbookBox, dataField: 'items' },
+ options: {
+ acl: '',
+ _height: 200,
+ _xMargin: 10,
+ _yMargin: 10,
+ _layout_fitWidth: false,
+ _layout_autoHeight: true,
+ _layout_reflowVertical: true,
+ _layout_reflowHorizontal: true,
+ _freeform_fitContentsToBox: true,
+ defaultDoubleClick: 'ignore',
+ systemIcon: 'BsImages',
+ },
+});