aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-08-31 11:50:14 -0400
committerbobzel <zzzman@gmail.com>2023-08-31 11:50:14 -0400
commit7c218639c75e22e1270d4198fb940b439175deee (patch)
treee09fd26ce9dd82d728b6c700ceb669cf22cc72ad
parent0c4f57875c8aaf599ff111a8b8122895d2addab3 (diff)
reworked recording workspace UI and switched to recording window, not webcam
-rw-r--r--src/client/util/CurrentUserUtils.ts58
-rw-r--r--src/client/util/DragManager.ts7
-rw-r--r--src/client/views/DashboardView.tsx8
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx90
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx215
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx3
-rw-r--r--src/client/views/topbar/TopBar.tsx63
-rw-r--r--src/fields/Doc.ts3
10 files changed, 234 insertions, 219 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 51ef51508..04f1ff0d2 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -18,6 +18,7 @@ import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
import { TreeViewType } from "../views/collections/CollectionTreeView";
import { DashboardView } from "../views/DashboardView";
import { Colors } from "../views/global/globalEnums";
+import { media_state } from "../views/nodes/AudioBox";
import { OpenWhere } from "../views/nodes/DocumentView";
import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
@@ -51,7 +52,7 @@ interface Button {
// fields that do not correspond to DocumentOption fields
scripts?: { script?: string; onClick?: string; onDoubleClick?: string }
- funcs?: { [key:string]: string };
+ funcs?: { [key:string]: any};
subMenu?: Button[];
}
@@ -591,7 +592,7 @@ export class CurrentUserUtils {
static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({
btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true,
_dropPropertiesToRemove: new List<string>([ "_layout_hideContextMenu"]),
- _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts,
+ /*_nativeWidth: 40, _nativeHeight: 40, */ _width: 40, _height: 40, isSystem: true, ...opts,
})
/// initializes the required buttons in the expanding button menu at the bottom of the Dash window
@@ -693,7 +694,6 @@ export class CurrentUserUtils {
{ title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script: '{ return webSetURL(value, _readOnly_); }'} },
];
}
-
static contextMenuTools():Button[] {
return [
{ btnList: new List<string>([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree,
@@ -701,11 +701,11 @@ export class CurrentUserUtils {
CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel,
CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map,
CollectionViewType.Grid, CollectionViewType.NoteTaking]),
- title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
+ 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: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}}, // Only when a document is selected
{ title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}},
- { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform
+ { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
{ title: "Num", icon:"", toolTip: "Frame Number (click to toggle edit mode)", btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
@@ -714,16 +714,8 @@ export class CurrentUserUtils {
{ title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
{ title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
{ title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
- { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected
- { title: "Video", icon: 'video', toolTip: "Dictate", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `getIsRecording()`}, ignoreClick: true, scripts: { onClick: 'return toggleRecording(_readOnly_)'}},
- { title: "StopRec", icon: "stop", toolTip: "Stop", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecording()`}, ignoreClick: true, scripts: { onClick: `return toggleRecording(_readOnly_)`}},
- { title: "Dropdown", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList, expertMode: false, funcs: {hidden: `renderDropdown()`, btnList: `getWorkspaceRecordings()`}, ignoreClick: true, scripts: { script: `toggleRecPlayback(value)`}},
- { title: "Play Rec",icon: "play", toolTip: "Play recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsWorkspaceRecPlaying()`}, ignoreClick: true, scripts: { onClick: `return playWorkspaceRec(getCurrentRecording())`}},
- { title: "Pause Rec",icon: "pause", toolTip: "Pause recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsWorkspaceRecPaused()`}, ignoreClick: true, scripts: { onClick: `return pauseWorkspaceRec(getCurrentRecording())`}},
- { title: "Stop Rec", icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `return closeWorkspaceRec(getCurrentRecording())`}},
- { title: "Add doc", icon: "down", toolTip: "add to doc", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `addRectoWorkspace(getCurrentRecording())`}},
- { title: "Delete Rec", icon: "trash", toolTip: "delete selected recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `removeWorkspaceRec(getCurrentRecording())`}}
- ];
+ { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected
+ ];
}
/// initializes a context menu button for the top bar context menu
@@ -749,19 +741,17 @@ export class CurrentUserUtils {
if (Doc.UserDoc().currentRecording) {
Doc.RemFromMyOverlay(DocCast(Doc.UserDoc().currentRecording));
}
- Doc.UserDoc().isRecording = false;
- Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().workspaceRecordingState = undefined;
+ Doc.UserDoc().workspaceReplayingState = undefined;
Doc.UserDoc().currentRecording = undefined;
- Doc.UserDoc().isPlaybackPlaying = false;
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = false;
+ Doc.UserDoc().workspaceRecordingState = undefined;
if (!subMenu) { // button does not have a sub menu
return this.setupContextMenuButton(params, menuBtnDoc);
}
// linear view
const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsOpen"]),
childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
- linearView_SubMenu: true, linearView_Expandable: params.btnType !== ButtonType.MultiToggleButton};
+ linearView_SubMenu: true, linearView_Expandable: true};
const items = (menuBtnDoc?:Doc) => !menuBtnDoc ? [] : subMenu.map(sub => this.setupContextMenuBtn(sub, menuBtnDoc) );
const creator = params.btnType === ButtonType.MultiToggleButton ? this.multiToggleList : this.linearButtonList;
@@ -773,11 +763,34 @@ export class CurrentUserUtils {
/// Initializes all the default buttons for the top bar context menu
static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
- const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true, linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
+ const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true, linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: true, _height: 35 };
const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => this.setupContextMenuBtn(params, ctxtMenuBtnsDoc) );
return DocUtils.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts, ctxtMenuBtns);
}
+ /// Initializes all the default buttons for the top bar context menu
+ static setupTopbarButtons(doc: Doc, field="myTopBarBtns") {
+ const dockedBtns = DocCast(doc[field]);
+ const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string|undefined}, funcs?: {[key:string]:any}) =>
+ DocUtils.AssignScripts(DocUtils.AssignOpts(DocListCast(dockedBtns?.data)?.find(doc => doc.title === opts.title), opts) ??
+ CurrentUserUtils.createToolButton(opts), scripts, funcs);
+
+ const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
+ { opts: { title: "Replicate",icon:"camera",toolTip: "Copy dashboard layout",btnType: ButtonType.ClickButton, expertMode: true}, scripts: { onClick: `snapshotDashboard()`}},
+ { opts: { title: "Recordings", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList,expertMode: false, ignoreClick: true, width: 100}, funcs: {hidden: `false`, btnList:`getWorkspaceRecordings()`}, scripts: { script: `{ return replayWorkspace(value, _readOnly_); }`}},
+ { opts: { title: "Stop Rec",icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `!isWorkspaceRecording()`}, scripts: { onClick: `stopWorkspaceRecording()`}},
+ { opts: { title: "Play", icon: "play", toolTip: "Play recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${media_state.Paused}"`}, scripts: { onClick: `resumeWorkspaceReplaying(getCurrentRecording())`}},
+ { opts: { title: "Pause", icon: "pause",toolTip: "Pause playback", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${media_state.Playing}"`}, scripts: { onClick: `pauseWorkspaceReplaying(getCurrentRecording())`}},
+ { opts: { title: "Stop", icon: "stop", toolTip: "Stop playback", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${media_state.Paused}"`}, scripts: { onClick: `stopWorkspaceReplaying(getCurrentRecording())`}},
+ { opts: { title: "Delete", icon: "trash",toolTip: "delete selected rec", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${media_state.Paused}"`}, scripts: { onClick: `removeWorkspaceReplaying(getCurrentRecording())`}}
+ ];
+ const btns = btnDescs.map(desc => dockBtn({_width: desc.opts.width??30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts, desc.funcs));
+ const dockBtnsReqdOpts:DocumentOptions = {
+ title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move',
+ childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: true, ignoreClick: true
+ };
+ return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns);
+ }
/// collection of documents rendered in the overlay layer above all tabs and other UI
static setupOverlays(doc: Doc, field = "myOverlayDocs") {
@@ -891,6 +904,7 @@ export class CurrentUserUtils {
this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard
this.setupPublished(doc); // sets up the list doc of all docs that have been published (meaning that they can be auto-linked by typing their title into another text box)
this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected
+ this.setupTopbarButtons(doc);
this.setupDockedButtons(doc); // the bottom bar of font icons
this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
this.setupDocTemplates(doc); // sets up the template menu of templates
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 065f17139..6c0641943 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -243,13 +243,10 @@ export namespace DragManager {
return dropDoc;
};
const finishDrag = async (e: DragCompleteEvent) => {
- Doc.UserDoc().isAddRecToDocMode = false;
Doc.RemFromMyOverlay(DocCast(Doc.UserDoc().currentRecording));
Doc.UserDoc().currentRecording = undefined;
- Doc.UserDoc().isRecPlayback = false;
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = false;
- Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.UserDoc().isWorkspaceReplaying = false;
+ Doc.UserDoc().workspaceRecordingState = undefined;
Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
const docDragData = e.docDragData;
dropEvent?.(); // glr: optional additional function to be called - in this case with presentation trails
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 4387c6e96..3ef6c0814 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -18,7 +18,7 @@ import { CollectionViewType } from '../documents/DocumentTypes';
import { HistoryUtil } from '../util/History';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { SharingManager } from '../util/SharingManager';
-import { undoBatch } from '../util/UndoManager';
+import { undoBatch, UndoManager } from '../util/UndoManager';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { CollectionView } from './collections/CollectionView';
import { ContextMenu } from './ContextMenu';
@@ -493,6 +493,8 @@ ScriptingGlobals.add(function resetDashboard(dashboard: Doc) {
ScriptingGlobals.add(function addToDashboards(dashboard: Doc) {
DashboardView.openDashboard(Doc.MakeEmbedding(dashboard));
}, 'adds Dashboard to set of Dashboards');
-ScriptingGlobals.add(function snapshotDashboard() {
- DashboardView.snapshotDashboard();
+ScriptingGlobals.add(async function snapshotDashboard() {
+ const batch = UndoManager.StartBatch('snapshot');
+ await DashboardView.snapshotDashboard();
+ batch.end();
}, 'creates a snapshot copy of a dashboard');
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 3481d5130..0cf7d4411 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -229,8 +229,8 @@ export class CollectionLinearView extends CollectionSubView() {
<div className="collectionLinearView" ref={this.createDashEventsTarget} onContextMenu={this.myContextMenu} style={{ minHeight: this.dimension(), pointerEvents: 'all' }}>
{
<>
- {menuOpener}
- {!this.layoutDoc.linearView_IsOpen ? null : (
+ {!this.layoutDoc.linearView_Expandable ? null :menuOpener}
+ {!this.layoutDoc.linearView_IsOpen && !this.layoutDoc.linearView_alwaysOpen ? null : (
<div
className="collectionLinearView-content"
style={{
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8a0706c30..998024cea 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -798,7 +798,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
!more && moreItems.length && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'compass' });
}
const constantItems: ContextMenuProps[] = [];
- if (!Doc.IsSystem(this.rootDoc)) {
+ if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._type_collection !== CollectionViewType.Docking) {
constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.props.Document) });
(this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' });
if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) {
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index bb2069cc9..8ef9cd792 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -180,55 +180,45 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
* Dropdown list
*/
@computed get dropdownListButton() {
- const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const script = ScriptCast(this.rootDoc.script);
let noviceList: string[] = [];
let text: string | undefined;
- let dropdown = true;
let getStyle: (val: string) => any = () => {};
let icon: IconProp = 'caret-down';
- let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView');
- try {
- if (isViewDropdown) {
- const selectedDocs: Doc[] = SelectionManager.Docs();
- const selected = SelectionManager.Docs().lastElement();
- if (selected) {
- if (StrCast(selected.type) === DocumentType.COL) {
- text = StrCast(selected._type_collection);
+ const isViewDropdown = script?.script.originalScript.startsWith('setView');
+ if (isViewDropdown) {
+ const selected = SelectionManager.Docs();
+ if (selected.lastElement()) {
+ if (StrCast(selected.lastElement().type) === DocumentType.COL) {
+ text = StrCast(selected.lastElement()._type_collection);
+ } else {
+ if (selected.length > 1) {
+ text = selected.length + ' selected';
} else {
- dropdown = false;
- if (selectedDocs.length > 1) {
- text = selectedDocs.length + ' selected';
- } else {
- text = Utils.cleanDocumentType(StrCast(selected.type) as DocumentType);
- icon = Doc.toIcon(selected);
- }
- return (
- <Popup
- icon={<FontAwesomeIcon size={'1x'} icon={icon} />}
- text={text}
- type={Type.TERT}
- color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
- popup={<SelectedDocView selectedDocs={selectedDocs} />}
- fillWidth
- />
- );
+ text = Utils.cleanDocumentType(StrCast(selected.lastElement().type) as DocumentType);
+ icon = Doc.toIcon(selected.lastElement());
}
- } else {
- dropdown = false;
- return <Button text="None Selected" type={Type.TERT} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} fillWidth inactive />;
+ return (
+ <Popup
+ icon={<FontAwesomeIcon size={'1x'} icon={icon} />}
+ text={text}
+ type={Type.TERT}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ popup={<SelectedDocView selectedDocs={selected} />}
+ fillWidth
+ />
+ );
}
- noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
} else {
- text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- getStyle = (val: string) => {
- return { fontFamily: val };
- };
+ return <Button text="None Selected" type={Type.TERT} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} fillWidth inactive />;
}
- } catch (e) {
- console.log(e);
+ noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
+ } else {
+ text = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result;
+ // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
+ getStyle = (val: string) => ({ fontFamily: val });
}
// Get items to place into the list
@@ -243,19 +233,17 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
}));
return (
- <div style={{ color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}>
- <Dropdown
- selectedVal={text}
- setSelectedVal={undoable(val => script.script.run({ this: this.layoutDoc, self: this.rootDoc, val }), `dropdown select ${this.label}`)}
- color={SettingsManager.userColor}
- background={isViewDropdown ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor}
- type={Type.TERT}
- dropdownType={DropdownType.SELECT}
- items={list}
- tooltip={this.label}
- fillWidth
- />
- </div>
+ <Dropdown
+ selectedVal={text ?? 'Record Workspace'}
+ setSelectedVal={undoable(val => script.script.run({ this: this.layoutDoc, self: this.rootDoc, val }), `dropdown select ${this.label}`)}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ type={Type.TERT}
+ dropdownType={DropdownType.SELECT}
+ items={list}
+ tooltip={this.label}
+ fillWidth
+ />
);
}
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 9dd673591..b1b044c25 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,11 +1,10 @@
import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { formatTime } from '../../../../Utils';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
import { listSpec } from '../../../../fields/Schema';
-import { BoolCast, Cast, DocCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast, StrCast } from '../../../../fields/Types';
import { VideoField } from '../../../../fields/URLField';
import { Upload } from '../../../../server/SharedMediaTypes';
import { Docs } from '../../../documents/Documents';
@@ -22,6 +21,8 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { VideoBox } from '../VideoBox';
import { RecordingView } from './RecordingView';
import { DateField } from '../../../../fields/DateField';
+import { media_state } from '../AudioBox';
+import { List } from '../../../../fields/List';
@observer
export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -41,9 +42,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@observable videoDuration: number | undefined = undefined;
@action
- setVideoDuration = (duration: number) => {
- this.videoDuration = duration;
- };
+ setVideoDuration = (duration: number) => (this.videoDuration = duration);
@action
setResult = (info: Upload.AccessPathInfo, presentation?: Presentation) => {
@@ -61,76 +60,68 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.dataDoc[this.fieldKey + '_presentation'] = JSON.stringify(presCopy);
}
};
-
- /**
- * This method toggles whether or not we are currently using the RecordingBox to record with the topbar button
- * @param _readOnly_
- * @returns
- */
@undoBatch
@action
- public static toggleWorkspaceRecording(_readOnly_: boolean) {
- if (_readOnly_) return RecordingBox.screengrabber ? true : false;
- if (RecordingBox.screengrabber) {
+ public static WorkspaceStopRecording() {
+ const remDoc = RecordingBox.screengrabber?.rootDoc;
+ if (remDoc) {
//if recordingbox is true; when we press the stop button. changed vals temporarily to see if changes happening
- console.log('grabbing screen!');
- RecordingBox.screengrabber.Pause?.();
- const remDoc = RecordingBox.screengrabber.rootDoc;
+ RecordingBox.screengrabber?.Pause?.();
setTimeout(() => {
RecordingBox.screengrabber?.Finish?.();
- RecordingBox.screengrabber!.rootDoc.overlayX = 70; //was 100
- RecordingBox.screengrabber!.rootDoc.overlayY = 590;
- console.log(RecordingBox.screengrabber);
+ remDoc.overlayX = 70; //was 100
+ remDoc.overlayY = 590;
RecordingBox.screengrabber = undefined;
}, 100);
//could break if recording takes too long to turn into videobox. If so, either increase time on setTimeout below or find diff place to do this
- setTimeout(() => {
- Doc.RemFromMyOverlay(remDoc);
- }, 1000);
- Doc.UserDoc().isRecording = false;
- Doc.AddDocToList(Doc.UserDoc(), 'workspaceRecordings', RecordingBox.screengrabber.rootDoc);
- } else {
- //when we first press mic
- const screengrabber = Docs.Create.WebCamDocument('', {
- title: `${Doc.ActiveDashboard?.title ?? ''} ${new DateField()}`,
- _width: 205,
- _height: 115,
- });
- screengrabber.overlayX = 70; //was -400
- screengrabber.overlayY = 590; //was 0
- screengrabber[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
- Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
- DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
- RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
- RecordingBox.screengrabber.Record?.();
- });
- Doc.UserDoc().isRecording = true;
+ setTimeout(() => Doc.RemFromMyOverlay(remDoc), 1000);
+ Doc.UserDoc().workspaceRecordingState = media_state.Paused;
+ Doc.AddDocToList(Doc.UserDoc(), 'workspaceRecordings', remDoc);
}
}
/**
+ * This method toggles whether or not we are currently using the RecordingBox to record with the topbar button
+ * @param _readOnly_
+ * @returns
+ */
+ @undoBatch
+ @action
+ public static WorkspaceStartRecording() {
+ const screengrabber = Docs.Create.ScreenshotDocument({
+ title: `${Doc.ActiveDashboard?.title ?? ''} ${new DateField()}`,
+ _width: 205,
+ _height: 115,
+ });
+ screengrabber.overlayX = 70; //was -400
+ screengrabber.overlayY = 590; //was 0
+ screengrabber[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
+ Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
+ DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
+ RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
+ RecordingBox.screengrabber.Record?.();
+ });
+ Doc.UserDoc().workspaceRecordingState = media_state.Recording;
+ }
+
+ /**
* This method changes the menu depending on whether or not we are in playback mode
* @param value RecordingBox rootdoc
*/
@undoBatch
@action
- public static toggleWorkspaceRecPlayback(value: Doc) {
+ public static replayWorkspace(value: Doc) {
Doc.UserDoc().currentRecording = value;
- console.log(value);
value.overlayX = 70;
value.overlayY = 590;
- if (!Doc.UserDoc().isAddRecToDocMode) {
- Doc.UserDoc().isRecPlayback = true;
- Doc.UserDoc().isWorkspaceRecPlaying = true;
- Doc.AddToMyOverlay(value);
- DocumentManager.Instance.AddViewRenderedCb(value, docView => {
- Doc.UserDoc().currentRecording = docView.rootDoc;
- SelectionManager.SelectSchemaViewDoc(value);
- });
- } else {
- let recordingIndex = DocListCast(Doc.UserDoc().workspaceRecordings).indexOf(value);
- DragManager.StartDropdownDrag([document.createElement('div')], new DragManager.DocumentDragData([value]), 1, 1, recordingIndex);
- }
+ Doc.AddToMyOverlay(value);
+ DocumentManager.Instance.AddViewRenderedCb(value, docView => {
+ Doc.UserDoc().currentRecording = docView.rootDoc;
+ SelectionManager.SelectSchemaViewDoc(value);
+ RecordingBox.resumeWorkspaceReplaying(value);
+ });
+ // let recordingIndex = DocListCast(Doc.UserDoc().workspaceRecordings).indexOf(value);
+ // DragManager.StartDropdownDrag([document.createElement('div')], new DragManager.DocumentDragData([value]), 1, 1, recordingIndex);
}
/**
@@ -140,62 +131,55 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
@action
public static addRecToWorkspace(value: RecordingBox) {
- console.log('adding rec to doc');
- console.log(value);
let ffView = Array.from(DocumentManager.Instance.DocumentViews).find(view => view.ComponentView instanceof CollectionFreeFormView);
(ffView?.ComponentView as CollectionFreeFormView).props.addDocument?.(value.rootDoc);
- let recordingIndex = DocListCast(Doc.UserDoc().workspaceRecordings).indexOf(value.rootDoc);
- console.log(recordingIndex);
- Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
- Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.RemoveDocFromList(Doc.UserDoc(), 'workspaceRecordings', value.rootDoc);
Doc.RemFromMyOverlay(value.rootDoc);
Doc.UserDoc().currentRecording = undefined;
- Doc.UserDoc().isRecPlayback = false;
- Doc.UserDoc().isAddRecToDocMode = false;
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = false;
+ Doc.UserDoc().workspaceReplayingState = undefined;
+ Doc.UserDoc().workspaceRecordingState = undefined;
}
@undoBatch
@action
- public static playWorkspaceRec(value: VideoBox) {
- value.Play();
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = true;
+ public static resumeWorkspaceReplaying(doc: Doc) {
+ const docView = DocumentManager.Instance.getDocumentView(doc);
+ const videoBox = docView?.ComponentView as VideoBox;
+ if (videoBox) {
+ videoBox.Play();
+ Doc.UserDoc().workspaceReplayingState = media_state.Playing;
+ }
}
@undoBatch
@action
- public static pauseWorkspaceRec(value: VideoBox) {
- value.Pause();
- Doc.UserDoc().isWorkspaceRecPlaying = true;
- Doc.UserDoc().isWorkspaceRecPaused = false;
+ public static pauseWorkspaceReplaying(doc: Doc) {
+ const docView = DocumentManager.Instance.getDocumentView(doc);
+ const videoBox = docView?.ComponentView as VideoBox;
+ if (videoBox) {
+ videoBox.Pause();
+ }
+ Doc.UserDoc().workspaceReplayingState = media_state.Paused;
}
@undoBatch
@action
- public static closeWorkspaceRec(value: VideoBox) {
- value.Pause();
- Doc.RemFromMyOverlay(value.rootDoc);
+ public static stopWorkspaceReplaying(value: Doc) {
+ Doc.RemFromMyOverlay(value);
Doc.UserDoc().currentRecording = undefined;
- Doc.UserDoc().isRecPlayback = false;
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = false;
- Doc.RemFromMyOverlay(value.rootDoc);
+ Doc.UserDoc().workspaceReplayingState = undefined;
+ Doc.UserDoc().workspaceRecordingState = undefined;
+ Doc.RemFromMyOverlay(value);
}
@undoBatch
@action
- public static removeWorkspaceRec(value: VideoBox) {
- let recordingIndex = DocListCast(Doc.UserDoc().workspaceRecordings).indexOf(value.rootDoc);
- Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
- Doc.UserDoc().isAddRecToDocMode = false;
- Doc.RemFromMyOverlay(value.rootDoc);
+ public static removeWorkspaceReplaying(value: Doc) {
+ Doc.RemoveDocFromList(Doc.UserDoc(), 'workspaceRecordings', value);
+ Doc.RemFromMyOverlay(value);
Doc.UserDoc().currentRecording = undefined;
- Doc.UserDoc().isRecPlayback = false;
- Doc.UserDoc().isAddRecToDocMode = false;
- Doc.UserDoc().isWorkspaceRecPlaying = false;
- Doc.UserDoc().isWorkspaceRecPaused = false;
+ Doc.UserDoc().workspaceReplayingState = undefined;
+ Doc.UserDoc().workspaceRecordingState = undefined;
}
Record: undefined | (() => void);
@@ -225,47 +209,44 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
static screengrabber: RecordingBox | undefined;
}
-ScriptingGlobals.add(function toggleRecording(_readOnly_: boolean) {
- RecordingBox.toggleWorkspaceRecording(_readOnly_);
-});
-ScriptingGlobals.add(function toggleRecPlayback(value: Doc) {
- RecordingBox.toggleWorkspaceRecPlayback(value);
+ScriptingGlobals.add(function startWorkspaceRecording() {
+ RecordingBox.WorkspaceStartRecording();
});
-ScriptingGlobals.add(function addRectoWorkspace(value: RecordingBox) {
- RecordingBox.addRecToWorkspace(value);
+ScriptingGlobals.add(function stopWorkspaceRecording() {
+ RecordingBox.WorkspaceStopRecording();
});
-ScriptingGlobals.add(function playWorkspaceRec(value: VideoBox) {
- RecordingBox.playWorkspaceRec(value);
+ScriptingGlobals.add(function stopWorkspaceReplaying(value: Doc) {
+ RecordingBox.stopWorkspaceReplaying(value);
});
-ScriptingGlobals.add(function pauseWorkspaceRec(value: VideoBox) {
- RecordingBox.pauseWorkspaceRec(value);
-});
-ScriptingGlobals.add(function closeWorkspaceRec(value: VideoBox) {
- RecordingBox.closeWorkspaceRec(value);
-});
-ScriptingGlobals.add(function removeWorkspaceRec(value: VideoBox) {
- RecordingBox.removeWorkspaceRec(value);
+ScriptingGlobals.add(function removeWorkspaceReplaying(value: Doc) {
+ RecordingBox.removeWorkspaceReplaying(value);
});
+ScriptingGlobals.add(function getCurrentRecording() {
+ return Doc.UserDoc().currentRecording;
+});
ScriptingGlobals.add(function getWorkspaceRecordings() {
- return Doc.UserDoc().workspaceRecordings;
+ return new List<any>(['Record Workspace', ...DocListCast(Doc.UserDoc().workspaceRecordings)]);
});
-ScriptingGlobals.add(function getIsRecording() {
- return Doc.UserDoc().isRecording;
+ScriptingGlobals.add(function isWorkspaceRecording() {
+ return Doc.UserDoc().workspaceRecordingState === media_state.Recording;
});
-ScriptingGlobals.add(function getIsRecPlayback() {
- return Doc.UserDoc().isRecPlayback;
+ScriptingGlobals.add(function isWorkspaceReplaying() {
+ return Doc.UserDoc().workspaceReplayingState;
});
-ScriptingGlobals.add(function getCurrentRecording() {
- return Doc.UserDoc().currentRecording;
+ScriptingGlobals.add(function replayWorkspace(value: Doc | string, _readOnly_: boolean) {
+ if (_readOnly_) return DocCast(Doc.UserDoc().currentRecording) ?? 'Record Workspace';
+ if (typeof value === 'string') RecordingBox.WorkspaceStartRecording();
+ else RecordingBox.replayWorkspace(value);
});
-ScriptingGlobals.add(function getIsWorkspaceRecPlaying() {
- return Doc.UserDoc().isWorkspaceRecPlaying;
+ScriptingGlobals.add(function pauseWorkspaceReplaying(value: Doc, _readOnly_: boolean) {
+ RecordingBox.pauseWorkspaceReplaying(value);
});
-ScriptingGlobals.add(function getIsWorkspaceRecPaused() {
- return Doc.UserDoc().isWorkspaceRecPaused;
+ScriptingGlobals.add(function resumeWorkspaceReplaying(value: Doc, _readOnly_: boolean) {
+ RecordingBox.resumeWorkspaceReplaying(value);
});
+
ScriptingGlobals.add(function renderDropdown() {
if (!Doc.UserDoc().workspaceRecordings || DocListCast(Doc.UserDoc().workspaceRecordings).length === 0) {
return true;
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index fa19caae1..4ebc93165 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -219,6 +219,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
// }
return null;
}
+ Record = () => !this._screenCapture && this.toggleRecording();
+ Pause = () => this._screenCapture && this.toggleRecording();
+
toggleRecording = async () => {
if (!this._screenCapture) {
this._audioRec = new MediaRecorder(await navigator.mediaDevices.getUserMedia({ audio: true }));
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 5b097e639..55d94406a 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,13 +1,14 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, isDark, Size, Toggle, Type } from 'browndash-components';
+import { Button, IconButton, isDark, Size, Type } from 'browndash-components';
import { action, computed, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { FaBug, FaCamera } from 'react-icons/fa';
+import { FaBug } from 'react-icons/fa';
import { Doc, DocListCast } from '../../../fields/Doc';
import { AclAdmin, DashVersion } from '../../../fields/DocSymbols';
import { StrCast } from '../../../fields/Types';
import { GetEffectiveAcl } from '../../../fields/util';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DocumentManager } from '../../util/DocumentManager';
import { PingManager } from '../../util/PingManager';
@@ -15,12 +16,14 @@ import { ReportManager } from '../../util/reportManager/ReportManager';
import { ServerStats } from '../../util/ServerStats';
import { SettingsManager } from '../../util/SettingsManager';
import { SharingManager } from '../../util/SharingManager';
-import { UndoManager } from '../../util/UndoManager';
+import { Transform } from '../../util/Transform';
import { CollectionDockingView } from '../collections/CollectionDockingView';
+import { CollectionLinearView } from '../collections/collectionLinear';
import { ContextMenu } from '../ContextMenu';
import { DashboardView } from '../DashboardView';
import { Colors } from '../global/globalEnums';
-import { DocumentView } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
+import { DefaultStyleProvider } from '../StyleProvider';
import './TopBar.scss';
/**
@@ -91,6 +94,43 @@ export class TopBar extends React.Component {
);
}
+ @computed get dashMenuButtons() {
+ const selDoc = Doc.MyTopBarBtns;
+ return !(selDoc instanceof Doc) ? null : (
+ <div className="collectionMenu-contMenuButtons" style={{ height: '100%' }}>
+ <CollectionLinearView
+ Document={selDoc}
+ DataDoc={undefined}
+ fieldKey="data"
+ dropAction="embed"
+ setHeight={returnFalse}
+ styleProvider={DefaultStyleProvider}
+ rootSelected={returnTrue}
+ bringToFront={emptyFunction}
+ select={emptyFunction}
+ isContentActive={returnTrue}
+ isAnyChildContentActive={returnFalse}
+ isSelected={returnFalse}
+ docViewPath={returnEmptyDoclist}
+ moveDocument={returnFalse}
+ addDocument={returnFalse}
+ addDocTab={DocumentViewInternal.addDocTabFunc}
+ pinToPres={emptyFunction}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={() => 200}
+ PanelHeight={() => 30}
+ renderDepth={0}
+ focus={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ />
+ </div>
+ );
+ }
+
/**
* Returns the center of the topbar
* This part of the topbar contains everything related to the current dashboard including:
@@ -118,23 +158,10 @@ export class TopBar extends React.Component {
style={{ fontWeight: 700, fontSize: '1rem' }}
onClick={(e: React.MouseEvent) => {
const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
- ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
dashView?.showContextMenu(e.clientX + 20, e.clientY + 30);
}}
/>
- {!Doc.noviceMode && (
- <IconButton
- tooltip="Work on a copy of the dashboard layout"
- size={Size.SMALL}
- color={this.color}
- onClick={async () => {
- const batch = UndoManager.StartBatch('snapshot');
- await DashboardView.snapshotDashboard();
- batch.end();
- }}
- icon={<FaCamera />}
- />
- )}
+ {!Doc.noviceMode && this.dashMenuButtons}
</div>
) : null;
}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ad0e548ed..2a1dfbfc7 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -220,6 +220,9 @@ export class Doc extends RefField {
public static get MyContextMenuBtns() {
return DocCast(Doc.UserDoc().myContextMenuBtns);
}
+ public static get MyTopBarBtns() {
+ return DocCast(Doc.UserDoc().myTopBarBtns);
+ }
public static get MyRecentlyClosed() {
return DocCast(Doc.UserDoc().myRecentlyClosed);
}