aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.DS_Storebin10244 -> 10244 bytes
-rw-r--r--src/client/documents/DocumentTypes.ts4
-rw-r--r--src/client/documents/Documents.ts51
-rw-r--r--src/client/util/CurrentUserUtils.ts14
-rw-r--r--src/client/views/DocComponent.tsx2
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss34
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx389
-rw-r--r--src/client/views/collections/CollectionMenu.tsx4
-rw-r--r--src/client/views/collections/CollectionView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx34
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx20
-rw-r--r--src/client/views/global/globalScripts.ts135
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx7
15 files changed, 646 insertions, 61 deletions
diff --git a/src/.DS_Store b/src/.DS_Store
index f8d745dbf..b464c99c8 100644
--- a/src/.DS_Store
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 1123bcac9..209b34f91 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -62,5 +62,7 @@ export enum CollectionViewType {
Pile = 'pileup',
StackedTimeline = 'stacked timeline',
NoteTaking = 'notetaking',
- Calendar = 'calendar'
+ Calendar = 'calendar',
+ Card = 'card'
+
}
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b160379df..1c57c5d63 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -498,6 +498,12 @@ export class DocumentOptions {
hoverBackgroundColor?: string; // background color of a label when hovered
userBackgroundColor?: STRt = new StrInfo('background color associated with a Dash user (seen in header fields of shared documents)');
userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
+
+ card_sort_time?: BOOLt = new BoolInfo('whether sorting cards in deck view by time');
+ card_sort_type?: BOOLt = new BoolInfo('whether sorting cards in deck view by type');
+ card_sort_color?: BOOLt = new BoolInfo('whether sorting cards in deck view by color');
+
+
}
export const DocOptions = new DocumentOptions();
@@ -1216,6 +1222,8 @@ export namespace Docs {
);
}
+
+
export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Linear }, id);
}
@@ -1232,6 +1240,10 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Carousel3D });
}
+ export function CardDeckDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Card});
+ }
+
export function SchemaDocument(schemaHeaders: SchemaHeaderField[], documents: Array<Doc>, options: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaHeaders: new List(schemaHeaders), ...options, _type_collection: CollectionViewType.Schema });
}
@@ -1881,6 +1893,45 @@ export namespace DocUtils {
return newCollection;
}
}
+
+ export function spreadCards(docList: Doc[], x: number = 0, y: number = 0, spreadAngle: number = 30, radius: number = 100, create: boolean = true) {
+ console.log('spread cards');
+ const totalCards = docList.length;
+ const halfSpreadAngle = spreadAngle * 0.5;
+ const angleStep = spreadAngle / (totalCards - 1);
+
+ runInAction(() => {
+ docList.forEach((d, i) => {
+ DocUtils.iconify(d);
+ const angle = (-halfSpreadAngle + angleStep * i) * (Math.PI / 180); // Convert degrees to radians
+ d.x = x + Math.cos(angle) * radius;
+ d.y = y + Math.sin(angle) * radius;
+ d.rotation = angle;
+ d._timecodeToShow = undefined;
+ });
+ });
+
+ if (create) {
+ const newCollection = Docs.Create.CardDeckDocument(docList, {
+ title: 'card-spread',
+ _freeform_noZoom: true,
+ x: x - radius,
+ y: y - radius,
+ _width: radius * 2,
+ _height: radius * 2,
+ dragWhenActive: true,
+ _layout_fitWidth: false
+ });
+ // Adjust position based on the collection's dimensions if needed
+ newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - radius;
+ newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - radius;
+ newCollection._width = newCollection._height = radius * 2;
+ return newCollection;
+ }
+ }
+
+
+
export function makeIntoPortal(doc: Doc, layoutDoc: Doc, allLinks: Doc[]) {
const portalLink = allLinks.find(d => d.link_anchor_1 === doc && d.link_relationship === 'portal to:portal from');
if (!portalLink) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 081115879..88fcf098b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -711,12 +711,23 @@ pie title Minerals in my tap water
{ title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
]
}
+ static cardTools(): Button[] {
+ return [
+ { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ClickButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ClickButton, expertMode: false, toolType:"docType", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ClickButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+
+ ]
+ }
static viewTools(): Button[] {
return [
{ title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
{ title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
{ title: "Fit All", icon: "object-group", toolTip: "Fit Docs to View (double click to make sticky)",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform
{ title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+
]
}
static textTools():Button[] {
@@ -793,7 +804,7 @@ pie title Minerals in my tap water
CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn,
CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel,
CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map,
- CollectionViewType.Grid, CollectionViewType.NoteTaking]),
+ CollectionViewType.Grid, CollectionViewType.NoteTaking, CollectionViewType.Card]),
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
{ title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} },
@@ -808,6 +819,7 @@ pie title Minerals in my tap water
{ title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Card", icon: "Sort", toolTip: "Card sort", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
{ title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
{ title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index de4df1830..ef4257937 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -35,7 +35,7 @@ export interface ViewBoxInterface {
addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
removeDocument?: (doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean, dontAddToRemoved?: boolean) => boolean; // add a document (used only by collections)
select?: (ctrlKey: boolean, shiftKey: boolean) => void;
- focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt<number>;
+ focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt<number>;
viewTransition?: () => Opt<string>; // duration of a view transition animation
isAnyChildContentActive?: () => boolean; // is any child content of the document active
onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 58b8d255a..abdb5abef 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -525,6 +525,8 @@ export class MainView extends ObservableReactComponent<{}> {
fa.faZ,
fa.faArrowsUpToLine,
fa.faArrowsDownToLine,
+ fa.faPalette,
+ fa.faHourglassHalf
]
);
}
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss
new file mode 100644
index 000000000..ff9c0a569
--- /dev/null
+++ b/src/client/views/collections/CollectionCardDeckView.scss
@@ -0,0 +1,34 @@
+@import '../global/globalCssVariables.module.scss';
+
+.collectionCardView-outer {
+ height: 100%;
+ position: relative;
+ background-color: white;
+ overflow: hidden;
+}
+
+.card-wrapper {
+ display: flex;
+ position: absolute;
+ align-items: center;
+ transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955);
+}
+
+.card-row{
+ display: flex;
+ position: absolute;
+ align-items: center;
+ transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955);
+
+
+}
+
+.card-item-active,
+.card-item {
+ transition: transform 0.3s ease-in-out;
+}
+
+.card-item-active {
+ position: absolute;
+ z-index: 100;
+}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
new file mode 100644
index 000000000..ab7aac267
--- /dev/null
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -0,0 +1,389 @@
+import { ObservableMap, action, computed, makeObservable, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Utils, returnFalse, returnTrue, returnZero } from '../../../Utils';
+import { Doc, DocListCast, Field } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { NumCast, ScriptCast, StrCast, BoolCast } from '../../../fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { SelectionManager } from '../../util/SelectionManager';
+import { StyleProp } from '../StyleProvider';
+import { DocumentView } from '../nodes/DocumentView';
+import './CollectionCardDeckView.scss';
+import { CollectionSubView } from './CollectionSubView';
+import { Transform } from '../../util/Transform';
+// import Card from 'react-bootstrap/Card';
+
+
+@observer
+export class CollectionCardView extends CollectionSubView() {
+ @observable selectedNodeIndex = -1;
+
+ @observable hoveredNodeIndex = -1;
+
+ @action
+ setHoveredNodeIndex = (index: number) => {
+ if (!this.isSelected(index)) {
+ this.hoveredNodeIndex = index;
+ }
+ };
+
+ translateHover = (index: number): number => {
+ if (this.hoveredNodeIndex == index && !this.isSelected(index)) {
+ return -50 * this.fitContentScale;
+ }
+ return 0;
+ };
+
+ @action
+ setSelectedNodeIndex = (index: number) => {
+ const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
+ console.log('goodnight');
+
+ if (SelectionManager.IsSelected(docs[index])) {
+ console.log('good mornings');
+ this.setSelectedNodeIndex(index);
+ }
+ };
+
+ isSelected = (index: number): boolean => {
+ const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
+
+ return SelectionManager.IsSelected(docs[index]);
+ };
+
+ inactiveDocs = () => {
+ const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
+
+
+
+ return docs.filter(d => !SelectionManager.IsSelected(d));
+ };
+
+ middleIndex = Math.floor(this.inactiveDocs().length / 2);
+
+ constructor(props: any) {
+ super(props);
+ makeObservable(this);
+ // this.rotationDegree(7);
+ }
+
+ private _dropDisposer?: DragManager.DragDropDisposer;
+
+ componentWillUnmount() {
+ this._dropDisposer?.();
+ }
+
+ protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
+ this._dropDisposer?.();
+ if (ele) {
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
+ }
+ };
+
+ childDocumentWidth = 600; // target width of a Doc...
+ /**
+ * how much to scale down the contents of the view so that everything will fit
+ */
+ @computed get fitContentScale() {
+ return (this.childDocumentWidth * this.childLayoutPairs.length) / this._props.PanelWidth();
+ }
+ panelWidth = () => this.childDocumentWidth;
+ panelHeight = (layout: Doc) => () => (2 * (this.panelWidth() * NumCast(layout._height))) / NumCast(layout._width);
+ onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
+ isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
+ isChildContentActive = () => (this.isContentActive() ? true : false);
+
+ rotate = (amCards: number, index: number) => {
+ console.log(amCards + "wtf")
+ const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2));
+ const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
+
+ // console.log(possRotate + "poss")
+
+ if (amCards % 2 == 0 && possRotate == 0) {
+ // console.log('whaddup');
+ return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
+ } else if (amCards % 2 == 0 && index > (amCards + 1) / 2) {
+ // console.log("sup" + stepMag);
+
+ return possRotate + stepMag;
+ }
+
+ return possRotate;
+ };
+
+ translateY = (amCards: number, index: number) => {
+ const evenOdd = amCards % 2;
+ const apex = (amCards - evenOdd) / 2;
+ const stepMag = 200 / ((amCards - evenOdd) / 2) + Math.abs((apex - index) * 25);
+
+ console.log('steo' + stepMag);
+
+ if (evenOdd == 1 || index < apex - 1) {
+ console.log('hi' + index);
+ return Math.abs(stepMag * (apex - index));
+ } else {
+ if (index == apex || index == apex - 1) {
+ return 0;
+ }
+
+ return Math.abs(stepMag * (apex - index - 1));
+ }
+ };
+
+ translateOverFlowY = (amCards: number, index: number) => {
+ if (amCards > 8 && index > amCards / 2) {
+ return 100;
+ }
+ return 0;
+ };
+
+ translateSelected = (index: number): number => {
+ if (this.isSelected(index)) {
+ const middleOfPanel = this._props.PanelWidth() / 2;
+ const scaledNodeWidth = this.panelWidth() * 1.25;
+
+ // Calculate the position of the node's left edge before scaling
+ const nodeLeftEdge = index * this.panelWidth();
+ // Find the center of the node after scaling
+ const scaledNodeCenter = nodeLeftEdge + scaledNodeWidth / 2;
+
+ // Calculate the translation needed to align the scaled node's center with the panel's center
+ const translation = middleOfPanel - scaledNodeCenter;
+
+ return translation;
+ }
+
+ return 0;
+ };
+
+ @computed get sortedDocsType() {
+
+ const desc = BoolCast(this.layoutDoc.sortDesc);
+
+ let sorted = []
+
+ for (let i=0; i< this.childLayoutPairs.length; i++){ //copying everything in childlayout pairs to sorted so that i can use the sort function without altering the original list
+ sorted[i] = this.childLayoutPairs[i]
+ }
+
+
+ // Copy and sort documents by type
+ const docs = sorted.sort((docA, docB) => {
+ const typeA = docA.layout.type ?? ''; // If docA.type is undefined, use an empty string
+ const typeB = docB.layout.type ?? ''; // If docB.type is undefined, use an empty string
+
+ // Perform a basic string comparison if types are strings
+ let out = 0;
+ if (typeA < typeB) out = -1;
+ if (typeA > typeB) out = 1;
+ if (desc) out *= -1; // Reverse the sort order if descending is true
+ return out;
+ });
+
+
+ return { docs };
+ }
+
+
+
+
+
+ @observable docRefs = new ObservableMap<Doc, DocumentView>();
+
+ @computed get contentSorted() {
+ const sortedDocs = this.sortedDocsType.docs;
+ const amCards = this.inactiveDocs().length;
+
+ const displayDoc = (childPair: { layout: Doc; data: Doc }, screenToLocalTransform: () => Transform) => {
+ return (
+ <DocumentView
+ {...this._props}
+ ref={action((r: DocumentView) => r?.ContentDiv && this.docRefs.set(childPair.layout, r))}
+ Document={childPair.layout}
+ TemplateDataDocument={childPair.data}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ layout_fitWidth={returnFalse}
+ onDoubleClickScript={this.onChildDoubleClick}
+ renderDepth={this._props.renderDepth + 1}
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ ScreenToLocalTransform={screenToLocalTransform}
+ isContentActive={this.isChildContentActive}
+ isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight(childPair.layout)}
+ />
+ );
+ };
+
+ // Map sorted documents to their rendered components
+ return sortedDocs.map((childPair, index) => {
+ // const childPair = { layout: doc, data: doc };
+ const isHovered = this.hoveredNodeIndex === index;
+ const inactiveIndex = this.sortedDocsType.docs.filter(d => !SelectionManager.IsSelected(d.layout)).indexOf(childPair);
+ const isSelected = SelectionManager.IsSelected(childPair.layout);
+
+
+
+
+ const childScreenToLocal = () => {
+ const dref = this.docRefs.get(childPair.layout);
+ const { translateX, translateY, scale } = Utils.GetScreenTransform(dref?.ContentDiv);
+ return new Transform(-translateX + (dref?.centeringX || 0) * scale, -translateY + (dref?.centeringY || 0) * scale, 1).scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, inactiveIndex) : 0);
+ };
+
+ return (
+ <div
+ key={childPair.layout[Id]}
+ className={`card-item${isSelected ? '-active' : ''}`}
+ style={{
+ width: this.panelWidth(),
+ height: this.panelHeight(childPair.layout)(),
+ transform: `
+ rotate(${!isSelected ? this.rotate(amCards, inactiveIndex) : 0}deg)
+ translateY(${isHovered ? this.translateHover(inactiveIndex) : isSelected ? 50 * this.fitContentScale : this.translateY(amCards, inactiveIndex)}px)
+ translateX(${isSelected ? (this._props.PanelWidth() / 2) * this.fitContentScale - this.childDocumentWidth : 0}px)
+ scale(${isSelected ? 1.25 : 1})
+ `,
+ }}
+ onMouseEnter={() => this.setHoveredNodeIndex(index)}>
+ {displayDoc(childPair, childScreenToLocal)}
+ </div>
+ );
+ });
+ }
+
+ @computed get content() {
+ // const currentIndex = NumCast(this.layoutDoc._carousel_index);
+ const amCards = this.inactiveDocs().length;
+ console.log(amCards + "lol")
+ // const sortedDocs = this.sortedDocsType.docs; // Retrieve sorted documents
+
+ // const myInactives =
+ const displayDoc = (childPair: { layout: Doc; data: Doc }, screenToLocalTransform: () => Transform) => {
+ return (
+ <DocumentView
+ {...this._props}
+ ref={action((r: DocumentView) => r?.ContentDiv && this.docRefs.set(childPair.layout, r))}
+ Document={childPair.layout}
+ TemplateDataDocument={childPair.data}
+ // onClickScript={this.toggleIcon}
+ //suppressSetHeight={true}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ layout_fitWidth={returnFalse}
+ onDoubleClickScript={this.onChildDoubleClick}
+ renderDepth={this._props.renderDepth + 1}
+ LayoutTemplate={this._props.childLayoutTemplate}
+ LayoutTemplateString={this._props.childLayoutString}
+ // focus={this.focus}
+ ScreenToLocalTransform={screenToLocalTransform} //makes sure the box wrapper thing is in the right spot
+ isContentActive={this.isChildContentActive}
+ isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight(childPair.layout)}
+ />
+ );
+ };
+
+ return this.childLayoutPairs.map((childPair, index) => {
+ const isSelected = this.isSelected(index);
+ const isHovered = this.hoveredNodeIndex === index;
+ const isOverflow = amCards > 8 && index > amCards / 2;
+ // const inactiveIndex = this.sortedDocsType.docs.indexOf(childPair);
+ const inactiveIndex = this.inactiveDocs().indexOf(childPair.layout);
+ // const yOffset = this.verticalOffset(index);
+
+ const childScreenToLocal = () => {
+ const dref = this.docRefs.get(childPair.layout);
+ const { translateX, translateY, scale } = Utils.GetScreenTransform(dref?.ContentDiv);
+ // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off
+ return new Transform(-translateX + (dref?.centeringX || 0) * scale, -translateY + (dref?.centeringY || 0) * scale, 1).scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, inactiveIndex) : 0);
+ };
+
+ return (
+ <div
+ key={childPair.layout[Id]}
+ className={`card-item${isSelected ? '-active' : ''}`}
+ style={{
+ width: this.panelWidth(),
+ height: this.panelHeight(childPair.layout)(),
+ transform: `
+ rotate(${!isSelected ? this.rotate(amCards, inactiveIndex) : 0}deg)
+ translateY(${isHovered ? this.translateHover(index) : isSelected ? 50 * this.fitContentScale : this.translateY(amCards, inactiveIndex)}px)
+ translateX(${isSelected ? (this._props.PanelWidth() / 2) * this.fitContentScale - this.childDocumentWidth : 0}px)
+ scale(${isSelected ? 1.25 : 1})
+
+ `, //scale has to be applied last or selected offset gets messed up
+ }}
+ // onClick={() => this.setSelectedNodeIndex(index)}
+
+ onMouseEnter={() => this.setHoveredNodeIndex(index)}>
+ {/* {this.lol(childPair.data, index)} */}
+
+ {displayDoc(childPair, childScreenToLocal)}
+ </div>
+ );
+ });
+ }
+
+ @computed get translateWrapperX() {
+ if (this.inactiveDocs().length != this.childLayoutPairs.length) {
+ return this.panelWidth() / 2;
+ }
+
+ return 0;
+ }
+
+ @computed get renderCardsSort(){
+ if (BoolCast(this._props.Document.card_sort_type) == true){
+ return this.contentSorted
+ }
+
+ else{
+ return this.content
+ }
+ }
+
+
+
+ render() {
+ return (
+ <div
+ className="collectionCardView-outer"
+ ref={this.createDashEventsTarget}
+ style={{
+ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor),
+ color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color),
+ }}>
+ <div
+ className="card-wrapper"
+ style={{
+ transform: ` scale(${1 / this.fitContentScale}) translateX(${this.translateWrapperX}px)`,
+ transformOrigin: 'top left',
+ height: `${100 * this.fitContentScale}%`,
+ }}
+ onMouseLeave={() => this.setHoveredNodeIndex(-1)}>
+ {this.renderCardsSort}
+ </div>
+
+ {/* <Card className={`custom-modal-position step-${step}`}>
+ <Card.Header>
+ {header}
+ <Button variant="close" className= "tut-close"onClick={store.toggleTutorial} style={{ position: 'absolute', top: 0, right: 0 }} />
+ </Card.Header>
+ <Card.Body>{body}
+ <Button className= 'next-step' variant="primary" onClick={store.nextStep}>Next Step!</Button>
+ </Card.Body>
+
+
+ </Card> */}
+
+ {/* {this.focusContent} */}
+ </div>
+ );
+ }
+}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 4f25f69ef..81d9f4eea 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -319,6 +319,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
return this._freeform_commands;
case CollectionViewType.Carousel3D:
return this._freeform_commands;
+ case CollectionViewType.Card:
+ return this._freeform_commands;
+
+
}
}
private _commandRef = React.createRef<HTMLInputElement>();
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 18eb4dd1f..b7805bf3f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -33,6 +33,8 @@ import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
+import { CollectionCardView } from './CollectionCardDeckView';
+
export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently)
@@ -134,6 +136,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
case CollectionViewType.Masonry: return <CollectionStackingView key="collview" {...props} />;
case CollectionViewType.Time: return <CollectionTimeView key="collview" {...props} />;
case CollectionViewType.Grid: return <CollectionGridView key="collview" {...props} />;
+ case CollectionViewType.Card: return <CollectionCardView key="collview" {...props} />;
+
+
}
};
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index c83c26509..becad63f6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -125,6 +125,40 @@ export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc
return normalizeResults(burstDiam, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]);
}
+// export function computeCardDeckLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
+// console.log('hi');
+// const docMap = new Map<string, PoolData>();
+// const spreadWidth = Math.min(panelDim[0], childPairs.length * 50); // Total width of the spread
+// const startX = -(spreadWidth / 2); // Starting X position
+// const fanAngle = 5; // Angle in degrees for fanning out cards
+// const baseZIndex = 1000; // Base Z-index to ensure cards are stacked in order
+
+// childPairs.forEach(({ layout, data }, i) => {
+// const aspect = NumCast(layout._height) / NumCast(layout._width);
+// const docSize = Math.min(400, NumCast(layout._width)) * NumCast(pivotDoc._starburstDocScale, 1);
+// const posX = startX + (spreadWidth / childPairs.length) * i;
+// const posY = 0; // Adjust if you want to change the vertical alignment
+// const rotation = (i - (childPairs.length / 2)) * fanAngle; // Calculate rotation for fanning effect
+
+// docMap.set(layout[Id], {
+// x: posX,
+// y: posY,
+// width: docSize,
+// height: docSize * aspect,
+// zIndex: baseZIndex + i,
+// rotation: rotation,
+// pair: { layout, data },
+// replica: '',
+// color: 'white',
+// backgroundColor: 'white',
+// transition: 'all 0.3s',
+// });
+// });
+
+// const divider = { type: 'div', color: 'transparent', x: -panelDim[0] / 2, y: -panelDim[1] / 2, width: 15, height: 15, payload: undefined };
+// return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]);
+// }
+
export function computePivotLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) {
const docMap = new Map<string, PoolData>();
const fieldKey = 'data';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 079a5d977..2d05b5490 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -49,7 +49,9 @@ import { CollectionSubView } from '../CollectionSubView';
import { TreeViewType } from '../CollectionTreeView';
import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid';
import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI';
-import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines';
+import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult,
+ // computeCardDeckLayout
+ } from './CollectionFreeFormLayoutEngines';
import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannableContents';
import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors';
import './CollectionFreeFormView.scss';
@@ -1383,6 +1385,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
case computeTimelineLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
case computePivotLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) };
case computeStarburstLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeStarburstLayout) };
+ // case computeCardDeckLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeCardDeckLayout) };
+
}
return { newPool, computedElementData: this.doFreeformLayout(newPool) };
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 6eca91e9d..98684ae98 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -385,6 +385,18 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
this.hideMarquee();
});
+ @undoBatch
+ spreadCards = action((e: KeyboardEvent | React.PointerEvent | undefined) => {
+ const selected = this.marqueeSelect(false);
+ SelectionManager.DeselectAll();
+ selected.forEach(d => this._props.removeDocument?.(d));
+ const newCollection = DocUtils.spreadCards(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2)!;
+ this._props.addDocument?.(newCollection);
+ this._props.selectDocuments([newCollection]);
+ MarqueeOptionsMenu.Instance.fadeOut(true);
+ this.hideMarquee();
+ });
+
/**
* This triggers the TabDocView.PinDoc method which is the universal method
* used to pin documents to the currently active presentation trail.
@@ -510,6 +522,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
@action
marqueeCommand = (e: KeyboardEvent) => {
+
if (this._commandExecuted || (e as any).propagationIsStopped) {
return;
}
@@ -520,7 +533,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
this.delete(e, e.key === 'h');
e.stopPropagation();
}
- if ('ctsSpg'.indexOf(e.key) !== -1) {
+ if ('ctsSpga'.indexOf(e.key) !== -1) {
+
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
@@ -528,7 +542,9 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
if (e.key === 'g') this.collection(e, true);
if (e.key === 'c' || e.key === 't') this.collection(e);
if (e.key === 's' || e.key === 'S') this.summary(e);
- if (e.key === 'p') this.pileup(e);
+ if (e.key === 'p') this.pileup(e)
+ // if (e.key === 'a') this.spreadCards(e);
+
this.cleanupInteractions(false);
}
if (e.key === 'r' || e.key === ' ') {
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 2a5732708..ffb1d751d 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -12,7 +12,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { UndoManager, undoable } from '../../util/UndoManager';
import { GestureOverlay } from '../GestureOverlay';
-import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke';
+import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke';
import { CollectionFreeFormView } from '../collections/collectionFreeForm';
// import { InkTranscription } from '../InkTranscription';
import { DocData } from '../../../fields/DocSymbols';
@@ -21,7 +21,6 @@ import { DocumentView } from '../nodes/DocumentView';
import { VideoBox } from '../nodes/VideoBox';
import { WebBox } from '../nodes/WebBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
-import { ImageBox } from '../nodes/ImageBox';
ScriptingGlobals.add(function IsNoneSelected() {
return SelectionManager.Views.length <= 0;
@@ -59,9 +58,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
obj[fieldKey] = color;
CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj);
} else {
- const dataKey = Doc.LayoutFieldKey(dv.Document);
- const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', '');
- dv.dataDoc[fieldKey + alternate] = color;
+ dv.Document[DocData][fieldKey] = color;
}
});
} else {
@@ -90,8 +87,8 @@ ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boole
});
} else {
Doc.SharingDoc().headingColor = undefined;
- Doc.GetProto(Doc.SharingDoc()).headingColor = color === 'transparent' ? undefined : color;
- Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'title');
+ Doc.GetProto(Doc.SharingDoc()).headingColor = color;
+ Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'author_date');
}
});
@@ -105,10 +102,10 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
selected ? selected.CollectionFreeFormDocumentView?.float() : console.log('[FontIconBox.tsx] toggleOverlay failed');
});
-ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce', checkResult?: boolean, persist?: boolean) {
+ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color', checkResult?: boolean, persist?: boolean) {
const selected = SelectionManager.Docs.lastElement();
// prettier-ignore
- const map: Map<'center' |'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([
+ const map: Map<'flashcards' | 'center' |'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([
['grid', {
checkResult: (doc:Doc) => BoolCast(doc?._freeform_backgroundGrid, false),
setDoc: (doc:Doc,dv:DocumentView) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid,
@@ -134,6 +131,23 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
checkResult: (doc:Doc) => BoolCast(doc?._freeform_useClusters, false),
setDoc: (doc:Doc,dv:DocumentView) => doc._freeform_useClusters = !doc._freeform_useClusters,
}],
+ ['flashcards', {
+ checkResult: (doc:Doc) => BoolCast(Doc.UserDoc().defaultToFlashcards, false),
+ setDoc: (doc:Doc,dv:DocumentView) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards,
+ }],
+ ['time', {
+ checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+ setDoc: (doc:Doc,dv:DocumentView) => doc.card_sort_time = !doc.card_sort_time,
+ }],
+ ['docType', {
+ checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+ setDoc: (doc:Doc,dv:DocumentView) => doc.card_sort_type = !doc.card_sort_type,
+ }],
+ ['color', {
+ checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+ setDoc: (doc:Doc,dv:DocumentView) => doc.card_sort_color = !doc.card_sort_color,
+ }],
+
]);
if (checkResult) {
@@ -144,6 +158,39 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
setTimeout(() => batch.end(), 100);
});
+// ScriptingGlobals.add(function setCardSortAttr(attr: 'time' | 'docType' | 'color', value: any, checkResult?: boolean) {
+// // const editorView = RichTextMenu.Instance?.TextView?.EditorView;
+// const selected = SelectionManager.Docs.lastElement();
+// // prettier-ignore
+// const map: Map<'time' | 'docType' | 'color', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([
+// ['time', {
+// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "time",
+// }],
+// ['docType', {
+// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "type",
+// }],
+// ['color', {
+// checkResult: (doc:Doc) => StrCast(doc?.cardSort),
+// setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "color",
+// }],
+// // ['custom', {
+// // checkResult: () => RichTextMenu.Instance.textAlign,
+// // setDoc: () => value && editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, value):(Doc.UserDoc().textAlign = value),
+// // }]
+// // ,
+// ]);
+
+// if (checkResult) {
+// return map.get(attr)?.checkResult(selected);
+// }
+
+// console.log('hey')
+// SelectionManager.Views.map(dv => map.get(attr)?.setDoc(dv.layoutDoc, dv));
+// console.log('success')
+// });
+
ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize' | 'alignment', value: any, checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
const selected = SelectionManager.Docs.lastElement();
@@ -151,26 +198,26 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
const map: Map<'font'|'fontColor'|'highlight'|'fontSize'|'alignment', { checkResult: () => any; setDoc: () => void;}> = new Map([
['font', {
checkResult: () => RichTextMenu.Instance?.fontFamily,
- setDoc: () => value && RichTextMenu.Instance?.setFontFamily(value),
+ setDoc: () => value && RichTextMenu.Instance.setFontFamily(value),
}],
['highlight', {
- checkResult: () => RichTextMenu.Instance?.fontHighlight,
- setDoc: () => value && RichTextMenu.Instance?.setHighlight(value),
+ checkResult: () =>(selected ?? Doc.UserDoc())._fontHighlight,
+ setDoc: () => value && RichTextMenu.Instance.setHighlight(value),
}],
['fontColor', {
checkResult: () => RichTextMenu.Instance?.fontColor,
- setDoc: () => value && RichTextMenu.Instance?.setColor(value),
+ setDoc: () => value && RichTextMenu.Instance.setColor(value),
}],
['alignment', {
- checkResult: () => RichTextMenu.Instance?.textAlign,
- setDoc: () => value && editorView?.state ? RichTextMenu.Instance?.align(editorView, editorView.dispatch, value):(Doc.UserDoc().textAlign = value),
+ checkResult: () => RichTextMenu.Instance.textAlign,
+ setDoc: () => value && editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, value):(Doc.UserDoc().textAlign = value),
}],
['fontSize', {
checkResult: () => RichTextMenu.Instance?.fontSize.replace('px', ''),
setDoc: () => {
if (typeof value === 'number') value = value.toString();
if (value && Number(value).toString() === value) value += 'px';
- RichTextMenu.Instance?.setFontSize(value);
+ RichTextMenu.Instance.setFontSize(value);
},
}],
]);
@@ -181,46 +228,48 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
map.get(attr)?.setDoc?.();
});
+
+
type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'elide' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal';
-type attrfuncs = [attrname, { checkResult: () => boolean; toggle?: () => any }];
+type attrfuncs = [attrname, { checkResult: () => boolean; toggle: () => any }];
ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: boolean) {
const textView = RichTextMenu.Instance?.TextView;
const editorView = textView?.EditorView;
// prettier-ignore
const alignments:attrfuncs[] = (['left','right','center','vcent'] as ("left"|"center"|"right"|"vcent")[]).map((where) =>
- [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? RichTextMenu.Instance?.textVcenter ?? false:
- (RichTextMenu.Instance?.textAlign === where)):
+ [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? RichTextMenu.Instance.textVcenter:
+ (RichTextMenu.Instance.textAlign === where)):
where === 'vcent' ? BoolCast(Doc.UserDoc()._layout_centered):
(Doc.UserDoc().textAlign ===where) ? true:false),
- toggle: () => (editorView?.state ? (where === 'vcent' ? RichTextMenu.Instance?.vcenterToggle(editorView, editorView.dispatch):
- RichTextMenu.Instance?.align(editorView, editorView.dispatch, where)):
+ toggle: () => (editorView?.state ? (where === 'vcent' ? RichTextMenu.Instance.vcenterToggle(editorView, editorView.dispatch):
+ RichTextMenu.Instance.align(editorView, editorView.dispatch, where)):
where === 'vcent' ? Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered:
(Doc.UserDoc().textAlign = where))}]); // prettier-ignore
// prettier-ignore
const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list =>
- [ list, { checkResult: () => (editorView ? RichTextMenu.Instance?.listStyle === list:false),
- toggle: () => editorView?.state && RichTextMenu.Instance?.changeListType(list) }]);
+ [ list, { checkResult: () => (editorView ? RichTextMenu.Instance.getActiveListStyle() === list:false),
+ toggle: () => editorView?.state && RichTextMenu.Instance.changeListType(list) }]);
// prettier-ignore
const attrs:attrfuncs[] = [
['dictation', { checkResult: () => textView?._recordingDictation ? true:false,
toggle: () => textView && runInAction(() => (textView._recordingDictation = !textView._recordingDictation)) }],
['elide', { checkResult: () => false,
toggle: () => editorView ? RichTextMenu.Instance?.elideSelection(): 0}],
- ['noAutoLink',{ checkResult: () => ((editorView && RichTextMenu.Instance?.noAutoLink) ?? false),
+ ['noAutoLink',{ checkResult: () => (editorView ? RichTextMenu.Instance.noAutoLink : false),
toggle: () => editorView && RichTextMenu.Instance?.toggleNoAutoLinkAnchor()}],
- ['bold', { checkResult: () => (editorView ? RichTextMenu.Instance?.bold??false : (Doc.UserDoc().fontWeight === 'bold') ? true:false),
- toggle: editorView ? RichTextMenu.Instance?.toggleBold : () => (Doc.UserDoc().fontWeight = Doc.UserDoc().fontWeight === 'bold' ? undefined : 'bold')}],
- ['italics', { checkResult: () => (editorView ? RichTextMenu.Instance?.italics ?? false : (Doc.UserDoc().fontStyle === 'italics') ? true:false),
- toggle: editorView ? RichTextMenu.Instance?.toggleItalics : () => (Doc.UserDoc().fontStyle = Doc.UserDoc().fontStyle === 'italics' ? undefined : 'italics')}],
- ['underline', { checkResult: () => (editorView ? RichTextMenu.Instance?.underline ?? false: (Doc.UserDoc().textDecoration === 'underline') ? true:false),
- toggle: editorView ? RichTextMenu.Instance?.toggleUnderline : () => (Doc.UserDoc().textDecoration = Doc.UserDoc().textDecoration === 'underline' ? undefined : 'underline') }]]
+ ['bold', { checkResult: () => (editorView ? RichTextMenu.Instance.bold : (Doc.UserDoc().fontWeight === 'bold') ? true:false),
+ toggle: editorView ? RichTextMenu.Instance.toggleBold : () => (Doc.UserDoc().fontWeight = Doc.UserDoc().fontWeight === 'bold' ? undefined : 'bold')}],
+ ['italics', { checkResult: () => (editorView ? RichTextMenu.Instance.italics : (Doc.UserDoc().fontStyle === 'italics') ? true:false),
+ toggle: editorView ? RichTextMenu.Instance.toggleItalics : () => (Doc.UserDoc().fontStyle = Doc.UserDoc().fontStyle === 'italics' ? undefined : 'italics')}],
+ ['underline', { checkResult: () => (editorView ? RichTextMenu.Instance.underline : (Doc.UserDoc().textDecoration === 'underline') ? true:false),
+ toggle: editorView ? RichTextMenu.Instance.toggleUnderline : () => (Doc.UserDoc().textDecoration = Doc.UserDoc().textDecoration === 'underline' ? undefined : 'underline') }]]
const map = new Map(attrs.concat(alignments).concat(listings));
if (checkResult) {
return map.get(charStyle)?.checkResult();
}
- undoable(() => map.get(charStyle)?.toggle?.(), 'toggle ' + charStyle)();
+ undoable(() => map.get(charStyle)?.toggle(), 'toggle ' + charStyle)();
});
export function checkInksToGroup() {
@@ -339,20 +388,15 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean,
ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode');
// toggle: Set overlay status of selected document
-ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) {
+ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) {
const selected = SelectionManager.Docs.lastElement() ?? Doc.UserDoc();
// prettier-ignore
- const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
+ const map: Map<'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
['inkMask', {
checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())),
setInk: (doc: Doc) => (doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask),
setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()),
}],
- ['labels', {
- checkResult: () => ((selected?._stroke_showLabel ? BoolCast(selected[DocData].stroke_showLabel) : ActiveInkHideTextLabels())),
- setInk: (doc: Doc) => (doc[DocData].stroke_showLabel = !doc.stroke_showLabel),
- setMode: () => selected?.type !== DocumentType.INK && SetActiveInkHideTextLabels(!ActiveInkHideTextLabels()),
- }],
['fillColor', {
checkResult: () => (selected?._layout_isSvg ? StrCast(selected[DocData].fillColor) : ActiveFillColor() ?? "transparent"),
setInk: (doc: Doc) => (doc[DocData].fillColor = StrCast(value)),
@@ -407,15 +451,6 @@ ScriptingGlobals.add(function videoSnapshot() {
selected?.Snapshot();
});
-ScriptingGlobals.add(function imageSetPixelSize() {
- const selected = SelectionManager.Views.lastElement()?.ComponentView as ImageBox;
- selected?.setNativeSize();
-});
-ScriptingGlobals.add(function imageRotate90() {
- const selected = SelectionManager.Views.lastElement()?.ComponentView as ImageBox;
- selected?.rotate();
-});
-
/** Schema
* toggleSchemaPreview
**/
@@ -448,10 +483,10 @@ ScriptingGlobals.add(function toggleSingleLineSchema(checkResult?: boolean) {
*/
ScriptingGlobals.add(function setGroupBy(key: string, checkResult?: boolean) {
SelectionManager.Docs.map(doc => (doc._text_fontFamily = key));
- const editorView = RichTextMenu.Instance?.TextView?.EditorView;
+ const editorView = RichTextMenu.Instance.TextView?.EditorView;
if (checkResult) {
- return StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc())?.fontFamily);
+ return StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
}
- if (editorView) RichTextMenu.Instance?.setFontFamily(key);
+ if (editorView) RichTextMenu.Instance.setFontFamily(key);
else Doc.UserDoc().fontFamily = key;
});
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 43010b2ed..f856d9637 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -972,11 +972,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight),
icon: this.Document._layout_autoHeight ? 'lock' : 'unlock',
});
- !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
- const help = cm.findByDescription('Help...');
- const helpItems = help && 'subitems' in help ? help.subitems : [];
- helpItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: <BsMarkdownFill /> });
- !help && cm.addItem({ description: 'Help...', subitems: helpItems, icon: 'eye' });
+ optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: <BsMarkdownFill /> });
+ !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'sliders' });
this._downX = this._downY = Number.NaN;
};