import { action, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { CollectionFreeFormView } from '.'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { ButtonType } from '../../nodes/FontIconBox/FontIconBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { CollectionFreeFormInfoState, InfoButton, infoState, InfoState } from './CollectionFreeFormInfoState'; export interface CollectionFreeFormInfoUIProps { Document: Doc; LayoutDoc: Doc; childDocs: () => Doc[]; close: () => void; } @observer export class CollectionFreeFormInfoUI extends ObservableReactComponent { private _originalBackground: string | undefined; private _tutorialStates: { [key: string]: infoState } = {}; public static Init() { CollectionFreeFormView.SetInfoUICreator((doc: Doc, layout: Doc, childDocs: () => Doc[], close: () => void) => ); } constructor(props: CollectionFreeFormInfoUIProps) { super(props); makeObservable(this); this._tutorialStates = {}; // Initialize an empty object this.currState = this.setupStates(); // Call setupStates() here } @observable _currState: infoState | undefined = undefined; @observable _nextState: infoState | undefined = undefined; // Track next state get currState() { return this._currState; } set currState(val) { runInAction(() => (this._currState = val)); } componentWillUnmount() { this._props.Document.backgroundColor = this._originalBackground; } skipToState = action((newState: infoState) => (this._currState = newState)); createNextButton = (newState: ReturnType) => { return { title: 'Next', toolTip: 'Next', btnType: ButtonType.ClickButton, scripts: { onClick: `this.skipToState(${newState})`, }, targetState: newState, }; }; setupStates = () => { let docCounter = this._props.childDocs().length; let lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; let linkCounter = Doc.Links(lastDocCreated)?.length; let presentationCounter = DocListCast(Doc.ActivePresentation?.data).length; this._originalBackground = this._props.Document.backgroundColor as string; this._tutorialStates.multipleDocs = InfoState( "Let's create a new link! Click the link icon on one document and connect it to another.", { linkStarted: [ () => DocumentLinksButton.StartLink, () => { linkCounter = Doc.Links(lastDocCreated).length; // eslint-disable-next-line no-use-before-define return startedLink; }, ], // docCreated: [() => this._props.childDocs().length > docCounter, () => { // docCounter += 1 // lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1] // // eslint-disable-next-line no-use-before-define // return this.tutorialStates.makePresentation}] }, 'dash-create-link-board.gif' ); this._tutorialStates.presentDocs = InfoState( "Select a document then click the 'pin' button in the top left to create your presentation.", { docPinned: [ () => DocListCast(Doc.ActivePresentation?.data).length > presentationCounter, () => { presentationCounter++; // eslint-disable-next-line no-use-before-define return pinnedDoc; }, ], }, 'pin-explanation.gif' ); this._tutorialStates.nestedCollections = InfoState( "Want to learn how to create a nested collection? Click the : button and add a 'collection' doc", { docCreated: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; // eslint-disable-next-line no-use-before-define return marqueeSelection; }, ], }, 'dash-nested-collection.gif' ); this._tutorialStates.makePresentation = InfoState('Add a new document to create a presentation!', { docCreated: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; return this._tutorialStates.presentDocs; }, ], }); const skipToLinksButton: InfoButton = { title: 'Links Tutorial', toolTip: 'Skip', btnType: ButtonType.ClickButton, scripts: { onClick: 'this.skipToState(this.tutorialStates.multipleDocs)', }, targetState: this._tutorialStates.multipleDocs, }; const skipToPinsButton: InfoButton = { title: 'Pins Tutorial', toolTip: 'Skip', btnType: ButtonType.ClickButton, scripts: { onClick: 'this.skipToState(this.tutorialStates.makePresentation)', }, targetState: this._tutorialStates.makePresentation, }; // const skipToPresentationButton: Button = { // title: "Collections Tutorial", // toolTip: "Skip", // btnType: ButtonType.ClickButton, // scripts: { // onClick: "this.skipToState(this.tutorialStates.nestedCollections)" // }, // targetState: this.tutorialStates.nestedCollections // }; const ending = InfoState("If you have any more questions, feel free to ask Dash's AI Bot!"); // Traditional tutorial const completed = InfoState('Eager to learn more? Click the ? icon in the top right corner to read our full documentation.', { docRemoved: [() => this._props.childDocs().length === 1, () => this._tutorialStates.start] }, 'documentation.png'); const penMode = InfoState("You're in pen mode! Click and drag to draw your first masterpiece, then click the Ink button once you're done.", { activePen: [() => Doc.ActiveTool !== InkTool.Ink, () => completed], }); const briefArtisticFeature = InfoState("Finally, want to explore the art feature of Dash? Click the 'Ink' button on the hotbar then click the pen button.", { penModeActivated: [() => Doc.ActiveTool === InkTool.Ink, () => penMode], }); const activatePresentation = InfoState('Lastly, click the linked node and start the presentation!', { presentation: [() => Doc.ActivePresentation?.presentation_status === 'auto', () => briefArtisticFeature], }); const deletePresentation = InfoState( "Cool! Click 'setOnClick to follow primary link' for your non-presentation doc and try deleting the presentation.", { docRemoved: [ () => this._props.childDocs().length < docCounter, () => { docCounter -= 1; return activatePresentation; }, ], }, 'onclick-node.gif' ); const trailedPresentation = InfoState( 'Try linking your presentation to the last doc you created (now highlighted).', { linkAdd: [ () => Doc.Links(lastDocCreated)?.length > linkCounter, () => { linkCounter += 1; return deletePresentation; }, ], docAdded: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; // Last doc that is not the presentation lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 2]; linkCounter = Doc.Links(lastDocCreated)?.length; return deletePresentation; }, ], }, 'link-presentation.gif' ); const pinnedPresentation = InfoState( 'Want to see something cool? Zoom out, click the trail button on the presentation, and drag it inside the canvas.', { docAdded: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; // Last doc that is not the presentation lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 2]; Doc.HighlightDoc(lastDocCreated); linkCounter = Doc.Links(lastDocCreated)?.length; return trailedPresentation; }, ], }, 'dash-trail-explanation.gif' ); const pinnedDoc2 = InfoState('You pinned another doc. Press autoplay to the right to show your presentation!', { autoPresentation: [() => Doc.ActivePresentation?.presentation_status === 'auto', () => pinnedPresentation], }); const pinnedDoc = InfoState('You just pinned your doc. Pin another doc to add to the presentation!', { addedDoc: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; return pinnedDoc; }, ], docPinned: [ () => DocListCast(Doc.ActivePresentation?.data).length > presentationCounter, () => { presentationCounter++; return pinnedDoc2; }, ], }); const editLink = InfoState( "Want to make your link visible? Click 'show link'.", { docCreated: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; return this._tutorialStates.makePresentation; }, ], }, 'show-link.gif' ); const madeLink = InfoState( 'You made your first link! You can view your links by selecting the blue dot.', { linkViewed: [ () => DocButtonState.Instance.LinkEditorDocView, () => { docCounter = this._props.childDocs().length; return editLink; }, ], }, 'dash-following-link.gif' ); const startedLink = InfoState( 'Now click the highlighted link icon on your other document.', { linkAdd: [ () => Doc.Links(lastDocCreated)?.length > linkCounter, () => { linkCounter += 1; return madeLink; }, ], }, 'dash-create-link-board.gif' ); this._tutorialStates.movedDoc = InfoState( "Great moves! Try creating a second document.", { docCreated: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1 lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1] return this._tutorialStates.multipleDocs } ], }, 'dash-colon-menu.gif'); // prettier-ignore this._tutorialStates.start = InfoState( "Welcome to Dash! Click anywhere and begin typing ':' to create your first document.", { docCreated: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; return this._tutorialStates.movedDoc; }, ], }, undefined, [skipToLinksButton, skipToPinsButton] ); // Information on created nested collections const createdMarquee = InfoState( 'Next, right click and drag a square to create the collection', { marqueeMade: [ () => this._props.childDocs().length < docCounter, () => { docCounter -= 1; return ending; }, ], }, 'dash-create-collection-marquee.gif' ); const marqueeSelection = InfoState('Want an easier way to make a collection of docs? First add two docs you want to make a collection of', { marqueeMade: [ () => this._props.childDocs().length > docCounter, () => { docCounter += 1; lastDocCreated = this._props.childDocs()[this.props.childDocs().length - 1]; return createdMarquee; }, ], }); // Explanation of importing const easierImport = InfoState('Or, for easier access, you can drag any of the accepted file types from your computer or a webpage and drop it into your dashboard. This includes images, videos, audio, pdfs, and more!', {}, 'dash-', [ this.createNextButton(ending), ]); this._tutorialStates.importFile = InfoState('Want to learn how to import a file? Import using the import menu on the left hand side', {}, 'dash-import.gif', [this.createNextButton(easierImport)]); // Editing documents // Accessed by right-clicking anywhere on the target document or selecting the three bars menu at the bottom of the document chrome const extraContentsOfDoc = InfoState('Lastly, all documents also have a context-sensitive toolbar. The toolbar contents vary depending on the document type.', {}, 'context-toolbar.png', [this.createNextButton(ending)]); const contentsofDoc = InfoState('You can access the context of a doc through right-clicking anywhere on the target document or selecting the three bars menu at the bottom of the document chrome', {}, 'dash-context-menu.gif', [ this.createNextButton(extraContentsOfDoc), ]); const propertiesofDoc = InfoState('You can also access the properties of a doc through the double arrows in the top right or the single arrow on the right edge of the screen', {}, 'dash-properties-pane.gif', [ this.createNextButton(contentsofDoc), ]); this._tutorialStates.editingDocuments = InfoState('Want to learn how to edit a document? Either left or right click the document', {}, 'document-chrome.png', [this.createNextButton(propertiesofDoc)]); return this._tutorialStates.start; }; render() { return !this.currState ? null : ( ); } }