diff options
-rw-r--r-- | src/client/util/RTFMarkup.tsx | 137 | ||||
-rw-r--r-- | src/client/util/ServerStats.tsx | 3 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/MainViewModal.tsx | 37 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextRules.ts | 7 |
7 files changed, 177 insertions, 23 deletions
diff --git a/src/client/util/RTFMarkup.tsx b/src/client/util/RTFMarkup.tsx new file mode 100644 index 000000000..306d151d7 --- /dev/null +++ b/src/client/util/RTFMarkup.tsx @@ -0,0 +1,137 @@ +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { MainViewModal } from '../views/MainViewModal'; + +@observer +export class RTFMarkup extends React.Component<{}> { + static Instance: RTFMarkup; + @observable private isOpen = false; // whether the SharingManager modal is open or not + + // private get linkVisible() { + // return this.targetDoc ? this.targetDoc["acl-" + PublicKey] !== SharingPermissions.None : false; + // } + + @action + public open = () => (this.isOpen = true); + + @action + public close = () => (this.isOpen = false); + + constructor(props: {}) { + super(props); + RTFMarkup.Instance = this; + } + + @observable _stats: { [key: string]: any } | undefined; + + /** + * @returns the main interface of the SharingManager. + */ + @computed get cheatSheet() { + return ( + <div style={{ textAlign: 'initial', height: '100%' }}> + <p> + <b style={{ fontSize: 'larger' }}>{`wiki:phrase`}</b> + {` display wikipedia page for entered text (terminate with carriage return)`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`#tag `}</b> + {` add hashtag metadata to document. e.g, #idea`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`#, ## ... ###### `}</b> + {` set heading style based on number of '#'s between 1 and 6`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`#tag `}</b> + {` add hashtag metadata to document. e.g, #idea`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`>> `}</b> + {` add a sidebar text document inline`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`\`\` `}</b> + {` create a code snippet block`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%% `}</b> + {` restore default styling`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%color `}</b> + {` changes text color styling. e.g., %green.`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%num `}</b> + {` set font size. e.g., %10 for 10pt font`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%eq `}</b> + {` creates an equation block for typeset math`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%alt `}</b> + {` switch between primary and alternate text (see bottom right Button for hover options).`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%f `}</b> + {` create an inline footnote`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%> `}</b> + {` create a bockquote section. Terminate with 2 carriage returns`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%( `}</b> + {` start a section of inline elidable text. Terminate the inline text with %)`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%q `}</b> + {` start a quoted block of text that’s indented on the left and right. Terminate with %q`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%d `}</b> + {` start a block text where the first line is indented`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%h `}</b> + {` start a block of text that begins with a hanging indent`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%[ `}</b> + {` left justify text`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%^ `}</b> + {` center text`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`%] `}</b> + {` right justify text`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`[:doctitle]] `}</b> + {` hyperlink to document specified by it’s title`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`[[fieldname]] `}</b> + {` display value of fieldname`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`[[fieldname=value]] `}</b> + {` assign value to fieldname of document and display it`} + </p> + <p> + <b style={{ fontSize: 'larger' }}>{`[[fieldname:doctitle]] `}</b> + {` show value of fieldname from doc specified by it’s title`} + </p> + </div> + ); + } + + render() { + return <MainViewModal contents={this.cheatSheet} isDisplayed={this.isOpen} interactive={true} closeOnExternalClick={this.close} />; + } +} diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx index 0ab411bff..f84ad8598 100644 --- a/src/client/util/ServerStats.tsx +++ b/src/client/util/ServerStats.tsx @@ -1,8 +1,7 @@ -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { MainViewModal } from '../views/MainViewModal'; -import { DocumentView } from '../views/nodes/DocumentView'; import './SharingManager.scss'; @observer diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 43f56dd8c..5af9a9f9a 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -14,7 +14,7 @@ import { StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; -import { Docs, DocUtils } from '../documents/Documents'; +import { Docs } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { CaptureManager } from '../util/CaptureManager'; import { DocumentManager } from '../util/DocumentManager'; @@ -22,11 +22,12 @@ import { GroupManager } from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; import { Hypothesis } from '../util/HypothesisUtils'; import { ReportManager } from '../util/ReportManager'; +import { RTFMarkup } from '../util/RTFMarkup'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { SelectionManager } from '../util/SelectionManager'; +import { ServerStats } from '../util/ServerStats'; import { ColorScheme, SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; -import { ServerStats } from '../util/ServerStats'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { TimelineMenu } from './animationtimeline/TimelineMenu'; @@ -41,7 +42,7 @@ import { DashboardView } from './DashboardView'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; import { GestureOverlay } from './GestureOverlay'; -import { TOPBAR_HEIGHT, LEFT_MENU_WIDTH } from './global/globalCssVariables.scss'; +import { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } from './global/globalCssVariables.scss'; import { Colors } from './global/globalEnums'; import { KeyManager } from './GlobalKeyHandler'; import { InkTranscription } from './InkTranscription'; @@ -971,6 +972,7 @@ export class MainView extends React.Component { <DictationOverlay /> <SharingManager /> <ServerStats /> + <RTFMarkup /> <SettingsManager /> <ReportManager /> <CaptureManager /> diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index 55dee005d..32997a944 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import "./MainViewModal.scss"; +import './MainViewModal.scss'; import { observer } from 'mobx-react'; export interface MainViewOverlayProps { @@ -15,31 +15,38 @@ export interface MainViewOverlayProps { @observer export class MainViewModal extends React.Component<MainViewOverlayProps> { - render() { const p = this.props; const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1; const overlayOpacity = p.overlayDisplayedOpacity || 0.4; - return !p.isDisplayed ? (null) : ( - <div className="mainViewModal-cont" style={{ - pointerEvents: p.isDisplayed && p.interactive ? "all" : "none" - }}> - <div className="dialogue-box" style={{ - borderColor: "black", - ...(p.dialogueBoxStyle || {}), - opacity: p.isDisplayed ? dialogueOpacity : 0 - }} > + return !p.isDisplayed ? null : ( + <div + className="mainViewModal-cont" + style={{ + pointerEvents: p.isDisplayed && p.interactive ? 'all' : 'none', + }}> + <div + className="dialogue-box" + style={{ + borderColor: 'black', + height: 'max-content', + overflow: 'auto', + maxHeight: '80%', + ...(p.dialogueBoxStyle || {}), + opacity: p.isDisplayed ? dialogueOpacity : 0, + }}> {p.contents} </div> - <div className="overlay" + <div + className="overlay" onClick={this.props?.closeOnExternalClick} style={{ - backgroundColor: "black", + backgroundColor: 'black', ...(p.overlayStyle || {}), - opacity: p.isDisplayed ? overlayOpacity : 0 + opacity: p.isDisplayed ? overlayOpacity : 0, }} /> </div> ); } -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 38aa8db55..d58a4c199 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -767,6 +767,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps const constantItems: ContextMenuProps[] = []; if (!Doc.IsSystem(this.rootDoc)) { + constantItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'layer-group' }); constantItems.push({ description: 'Export as Zip file', icon: 'download', event: async () => Doc.Zip(this.props.Document) }); constantItems.push({ description: 'Import Zipped file', icon: 'upload', event: ({ x, y }) => this.importDocument() }); (this.rootDoc._viewType !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); @@ -774,11 +775,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); } - cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); + cm.addItem({ description: 'General...', noexpand: true, subitems: constantItems, icon: 'question' }); } const help = cm.findByDescription('Help...'); const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; - helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'layer-group' }); !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DataSym]), icon: 'hand-point-right' }); @@ -825,7 +825,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps icon: 'book', }); } - if (!help) cm.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'question' }); + if (!help) cm.addItem({ description: 'Help...', noexpand: !Doc.noviceMode, subitems: helpItems, icon: 'question' }); else cm.moveAfter(help); e?.stopPropagation(); // DocumentViews should stop propagation of this event diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 399e6bfdf..0610d1e45 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -68,6 +68,7 @@ import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); import React = require('react'); +import { RTFMarkup } from '../../../util/RTFMarkup'; const translateGoogleApi = require('translate-google-api'); export const GoogleRef = 'googleDocId'; type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void; @@ -858,6 +859,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps icon: !this.Document._singleLine ? 'grip-lines' : 'bars', }); optionItems.push({ description: `${this.Document._autoHeight ? 'Lock' : 'Auto'} Height`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: this.Document._autoHeight ? 'lock' : 'unlock' }); + optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: 'text' }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); this._downX = this._downY = Number.NaN; }; diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 599f96bca..20ce929ad 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -8,6 +8,7 @@ import { normalizeEmail } from '../../../../fields/util'; import { Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; +import { RTFMarkup } from '../../../util/RTFMarkup'; import { FormattedTextBox } from './FormattedTextBox'; import { wrappingInputRule } from './prosemirrorPatches'; import { RichTextMenu } from './RichTextMenu'; @@ -228,6 +229,12 @@ export class RichTextRules { return null; }), + // show markup help + new InputRule(new RegExp(/%\?$/), (state, match, start, end) => { + setTimeout(RTFMarkup.Instance.open); + return state.tr.deleteRange(start, end); + }), + // stop using active style new InputRule(new RegExp(/%alt$/), (state, match, start, end) => { setTimeout(() => (this.Document[this.TextBox.props.fieldKey + '-usePath'] = this.Document[this.TextBox.props.fieldKey + '-usePath'] ? undefined : 'alternate')); |