aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CaptureManager.scss18
-rw-r--r--src/client/util/CurrentUserUtils.ts115
-rw-r--r--src/client/util/DropConverter.ts2
-rw-r--r--src/client/util/GroupManager.scss6
-rw-r--r--src/client/util/ReportManager.tsx4
-rw-r--r--src/client/util/SettingsManager.scss141
-rw-r--r--src/client/util/SettingsManager.tsx470
-rw-r--r--src/client/util/SharingManager.scss6
8 files changed, 383 insertions, 379 deletions
diff --git a/src/client/util/CaptureManager.scss b/src/client/util/CaptureManager.scss
index a5024247e..11e31fe2e 100644
--- a/src/client/util/CaptureManager.scss
+++ b/src/client/util/CaptureManager.scss
@@ -155,21 +155,3 @@
}
}
-.close-button {
- position: absolute;
- top: 10;
- right: 10;
- background:transparent;
- border-radius:100%;
- width: 25px;
- height: 25px;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: 0.2s;
-}
-
-.close-button:hover {
- background: rgba(0,0,0,0.1);
-}
-
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7d0b477e2..4481933d5 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -12,7 +12,7 @@ import { Cast, DateCast, DocCast, StrCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
import { SetCachedGroups, SharingPermissions } from "../../fields/util";
import { GestureUtils } from "../../pen-gestures/GestureUtils";
-import { OmitKeys, Utils } from "../../Utils";
+import { OmitKeys, Utils, addStyleSheetRule } from "../../Utils";
import { DocServer } from "../DocServer";
import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents";
import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
@@ -20,7 +20,7 @@ import { TreeViewType } from "../views/collections/CollectionTreeView";
import { DashboardView } from "../views/DashboardView";
import { Colors } from "../views/global/globalEnums";
import { MainView } from "../views/MainView";
-import { ButtonType } from "../views/nodes/button/FontIconBox";
+import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
import { OpenWhere } from "../views/nodes/DocumentView";
import { OverlayView } from "../views/OverlayView";
import { DragManager, dropActionType } from "./DragManager";
@@ -28,7 +28,7 @@ import { MakeTemplate } from "./DropConverter";
import { FollowLinkScript } from "./LinkFollower";
import { LinkManager } from "./LinkManager";
import { ScriptingGlobals } from "./ScriptingGlobals";
-import { ColorScheme } from "./SettingsManager";
+import { ColorScheme, SettingsManager } from "./SettingsManager";
import { UndoManager } from "./UndoManager";
interface Button {
@@ -338,19 +338,19 @@ export class CurrentUserUtils {
}
/// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
- static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
+ static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
- { title: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
- { title: "Search", target: this.setupSearcher(doc, "mySearcher"), icon: "search", },
- { title: "Files", target: this.setupFilesystem(doc, "myFilesystem"), icon: "folder-open", },
- { title: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), icon: "wrench", funcs: {hidden: "IsNoviceMode()"} },
- { title: "Imports", target: this.setupImportSidebar(doc, "myImports"), icon: "upload", },
- { title: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive", },
- { title: "Shared Docs", target: Doc.MySharedDocs, icon: "users", funcs: {badgeValue:badgeValue}},
- { title: "Trails", target: Doc.UserDoc(), icon: "pres-trail", funcs: {target: getActiveDashTrails}},
- { title: "User Doc View", target: this.setupUserDocView(doc, "myUserDocView"), icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Dashboards", toolTip: "Dashboards ⌘D", target: this.setupDashboards(doc, "myDashboards"), icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), icon: "search", },
+ { title: "Files", toolTip: "Files ⌘⇧F", target: this.setupFilesystem(doc, "myFilesystem"), icon: "folder-open", },
+ { title: "Tools", toolTip: "Tools ⌘T", target: this.setupToolsBtnPanel(doc, "myTools"), icon: "wrench", funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), icon: "upload", },
+ { title: "Closed", toolTip: "Recently Closed ⌘R", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive", },
+ { title: "Shared", toolTip: "Shared Docs ⌘⇧S", target: Doc.MySharedDocs, icon: "users", funcs: {badgeValue:badgeValue}},
+ { title: "Trails", toolTip: "Trails ⌘⇧", target: Doc.UserDoc(), icon: "pres-trail", funcs: {target: getActiveDashTrails}},
+ { title: "User Doc", toolTip: "User Doc ⌘U", target: this.setupUserDocView(doc, "myUserDocView"), icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(self)'}}));
}
@@ -363,17 +363,17 @@ export class CurrentUserUtils {
static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
this.setupLeftSidebarPanel(doc);
const myLeftSidebarMenu = DocCast(doc[field]);
- const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => {
+ const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, scripts, funcs }) => {
const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
const reqdBtnOpts:DocumentOptions = {
- title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+ title, icon, target, toolTip, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
_width: 60, _height: 60, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
};
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
});
const reqdStackOpts:DocumentOptions ={
- title: "menuItemPanel", childDragAction: "same", backgroundColor: Colors.DARK_GRAY, layout_boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true,
+ title: "menuItemPanel", childDragAction: "same", layout_boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true,
_chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true,
};
return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" });
@@ -523,7 +523,7 @@ export class CurrentUserUtils {
const newFolder = `TreeView_addNewFolder()`;
const newFolderOpts: DocumentOptions = {
_forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeViewSortCriterion']),
- title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
+ title: "New folder", color: Colors.BLACK, btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
};
const newFolderScript = { onClick: newFolder};
const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
@@ -557,7 +557,7 @@ export class CurrentUserUtils {
const clearAll = (target:string) => `getProto(${target}).data = new List([])`;
const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
- title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, buttonText: "Empty", icon: "trash", isSystem: true,
+ title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, color: Colors.BLACK, buttonText: "Empty", icon: "trash", isSystem: true,
toolTip: "Empty recently closed",};
DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
@@ -600,8 +600,8 @@ export class CurrentUserUtils {
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
- { scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
- { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
+ { scripts: { onClick: "undo()"}, opts: { title: "Undo", icon: "undo-alt", toolTip: "Undo ⌘Z" }},
+ { scripts: { onClick: "redo()"}, opts: { title: "Redo", icon: "redo-alt", toolTip: "Redo ⌘R" }},
{ scripts: { }, opts: { title: "undoStack", layout: "<UndoStack>", toolTip: "Undo/Redo Stack"}}, // note: layout fields are hacks -- they don't actually run through the JSX parser (yet)
{ scripts: { }, opts: { title: "linker", layout: "<LinkingUI>", toolTip: "link started"}},
{ scripts: { }, opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}},
@@ -609,10 +609,10 @@ export class CurrentUserUtils {
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts:DocumentOptions = {
title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move',
- childDontRegisterViews: true, linearView_IsExpanded: true, linearView_Expandable: true, ignoreClick: true
+ childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: true, ignoreClick: true
};
- reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
- reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
+ reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "Redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
+ reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "Undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns);
}
@@ -625,29 +625,33 @@ export class CurrentUserUtils {
}
static viewTools(): Button[] {
return [
- { title: "Snap\xA0Lines", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "View\xA0All", icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "Arrange",icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform
+ { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "View All", icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Arrange",icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
]
}
static textTools():Button[] {
return [
{ title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) },
- { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, width: 75, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0 },
+ { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 },
{ title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}},
- { title: "Highlight",toolTip:"Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Highlight",toolTip:"Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} },
{ title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
- { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
- { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
- { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+ { title: "Alignment",toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},
+ subMenu: [
+ { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
+ { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+ { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+ ]
+ },
{ title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}},
{ title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
// { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
@@ -693,19 +697,19 @@ export class CurrentUserUtils {
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: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 20, scripts: { onClick: 'pinWithView(altKey)'}},
- { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected
- { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}},
- { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '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: 20, 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: 20, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
- { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
- { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: { linearView_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
- { 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_IsExpanded: `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_IsExpanded: `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_IsExpanded: `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_IsExpanded: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} } // Only when Schema is selected
+ { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}},
+ { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // 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_)'}},
+ { 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_)'}},
+ { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
+ { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+ { 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
];
}
@@ -713,7 +717,6 @@ export class CurrentUserUtils {
static setupContextMenuButton(params:Button, btnDoc?:Doc) {
const reqdOpts:DocumentOptions = {
...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
- backgroundColor: params.backgroundColor ??"transparent", /// a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below). Otherwise, assume a transparent background
color: Colors.WHITE, isSystem: true,
_nativeWidth: params.width ?? 30, _width: params.width ?? 30,
_height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
@@ -722,21 +725,20 @@ export class CurrentUserUtils {
};
const reqdFuncs:{[key:string]:any} = {
...params.funcs,
- backgroundColor: params.btnType === ButtonType.ToggleButton ? params.scripts?.onClick:undefined /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally
}
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs);
}
/// 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_IsExpanded"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true, linearView_IsExpanded: 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: false, _height: 35 };
const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => {
const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title);
- if (!params.subMenu) {
+ if (!params.subMenu) { // button does not have a sub menu
return this.setupContextMenuButton(params, menuBtnDoc);
- } else {
- const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsExpanded"]),
+ } else { // 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: true, };
const items = params.subMenu?.map(sub =>
@@ -810,7 +812,7 @@ export class CurrentUserUtils {
const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts);
const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer",
- _width: 30, _height: 30, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton,
+ _width: 30, _height: 30, color: Colors.BLACK, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton,
buttonText: "Import", icon: "upload", isSystem: true };
DocUtils.AssignDocField(myImports, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" });
return myImports;
@@ -848,6 +850,11 @@ export class CurrentUserUtils {
doc.fontHighlight ?? (doc.fontHighlight = "");
doc.defaultAclPrivate ?? (doc.defaultAclPrivate = false);
doc.savedFilters ?? (doc.savedFilters = new List<Doc>());
+ doc.userBackgroundColor ?? (doc.userBackgroundColor = Colors.DARK_GRAY);
+ addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: `${doc.userBackgroundColor} !important` });
+ doc.userVariantColor ?? (doc.userVariantColor = Colors.MEDIUM_BLUE);
+ doc.userColor ?? (doc.userColor = Colors.LIGHT_GRAY);
+ doc.userTheme ?? (doc.userTheme = ColorScheme.Dark);
doc.filterDocCount = 0;
doc.treeViewFreezeChildren = "remove|add";
doc.activePage = doc.activeDashboard === undefined ? 'home': doc.activePage;
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 47997cc5c..f235be192 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -9,7 +9,7 @@ import { RichTextField } from '../../fields/RichTextField';
import { ImageField } from '../../fields/URLField';
import { ScriptingGlobals } from './ScriptingGlobals';
import { listSpec } from '../../fields/Schema';
-import { ButtonType } from '../views/nodes/button/FontIconBox';
+import { ButtonType } from '../views/nodes/FontIconBox/FontIconBox';
export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = '') {
if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated
diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss
index 3157190bb..253ed5d2a 100644
--- a/src/client/util/GroupManager.scss
+++ b/src/client/util/GroupManager.scss
@@ -68,10 +68,8 @@
.close-button {
position: absolute;
- right: 1em;
- top: 1em;
- cursor: pointer;
- z-index: 999;
+ right: 2px;
+ top: 2px;
}
.group-heading {
diff --git a/src/client/util/ReportManager.tsx b/src/client/util/ReportManager.tsx
index 4c1020455..89c17e42f 100644
--- a/src/client/util/ReportManager.tsx
+++ b/src/client/util/ReportManager.tsx
@@ -11,7 +11,7 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/button/FontIconBox';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
import { DragManager } from './DragManager';
import { GroupManager } from './GroupManager';
import './SettingsManager.scss';
@@ -290,7 +290,7 @@ export class ReportManager extends React.Component<{}> {
isDisplayed={this.isOpen}
interactive={true}
closeOnExternalClick={this.close}
- dialogueBoxStyle={{ width: 'auto', height: '500px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }}
+ dialogueBoxStyle={{ width: 'auto', height: '500px', background: Cast(Doc.UserDoc().userColor, 'string', null) }}
/>
);
}
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index 1289ca2b4..bca649bc3 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -2,41 +2,20 @@
.settings-interface {
//background-color: whitesmoke !important;
- color: grey;
width: 450px;
-
- button {
- background: #315a96;
- outline: none;
- border-radius: 5px;
- border: 0px;
- color: #fcfbf7;
- text-transform: uppercase;
- letter-spacing: 2px;
- font-size: 75%;
- padding: 10px;
- margin: 10px;
- transition: transform 0.2s;
- margin: 2px;
- }
}
.settings-title {
font-size: 25px;
font-weight: bold;
padding-right: 10px;
- color: black;
}
.settings-username {
font-size: 12px;
padding-right: 15px;
- color: black;
margin-top: 10px;
margin-bottom: 10px;
- /* right: 135; */
- // position: absolute;
- // left: 243;
}
.settings-section {
@@ -49,7 +28,6 @@
font-size: 16;
font-weight: bold;
text-align: left;
- color: black;
width: 80;
margin-right: 50px;
}
@@ -61,40 +39,10 @@
.password-content {
display: flex;
+ width: 100%;
flex-direction: column;
-
- .password-content-inputs {
- width: 100;
- // margin-bottom: 10px;
- font-size: 10px;
-
- .password-inputs {
- border: 1px solid rgb(160, 160, 160);
- margin-bottom: 8px;
- width: 130;
- color: black;
- border-radius: 5px;
- padding: 7px;
- }
- }
-
- .password-content-buttons {
- //margin-left: 84px;
- //width: 100;
- padding: 7px;
-
- .password-submit {
- //margin-left: 85px;
- margin-top: 5px;
- }
-
- .password-forgot {
- //margin-left: 65px;
- //margin-top: -20px;
- font-size: 12px;
- white-space: nowrap;
- }
- }
+ align-items: flex-start;
+ gap: 5px;
}
.accounts-content {
@@ -103,7 +51,6 @@
.modes-content {
display: flex;
- margin-left: 10px;
font-size: 12px;
.modes-select {
@@ -111,7 +58,6 @@
width: 80%;
height: 35px;
margin-right: 10px;
- color: black;
border-radius: 5px;
&:hover {
@@ -135,12 +81,6 @@
}
}
- .playground-text {
- color: black;
- margin-right: 10px;
- margin-top: 2;
- }
-
.acl-text {
color: black;
margin-top: 2;
@@ -172,12 +112,11 @@
.appearances-content {
display: flex;
- margin-top: 4px;
- color: black;
font-size: 10px;
.preferences-color {
display: flex;
+ align-items: center;
margin-top: 2px;
.preferences-color-text {
@@ -197,7 +136,6 @@
margin-top: 2px;
.preferences-font-text {
- color: black;
margin-top: 4;
margin-right: 4;
margin-bottom: 2px;
@@ -212,7 +150,6 @@
.font-select {
height: 35px;
- color: black;
font-size: 9;
margin-right: 6;
border-radius: 5px;
@@ -225,7 +162,6 @@
.size-select {
height: 35px;
- color: black;
font-size: 9;
border-radius: 5px;
width: 30%;
@@ -237,7 +173,6 @@
}
.preferences-check {
- color: black;
margin-right: 4;
margin-bottom: -3;
margin-left: 5;
@@ -252,40 +187,17 @@
display: flex;
flex-direction: column;
- button {
- width: auto;
- align-self: center;
- background: #252b33;
- margin-right: 15px;
-
- //margin-top: 4px;
-
- &:hover {
- background: $medium-gray;
- }
- }
-
- // .delete-button {
- // background: rgb(227, 86, 86);
- // }
.close-button {
position: absolute;
- right: 1em;
- top: 1em;
- cursor: pointer;
+ right: 2px;
+ top: 2px;
}
- // .logout-button {
- // right: 355;
- // position: absolute;
- // }
.settings-content {
- background: #e4e4e4;
- //border-radius: 6px;
padding: 10px;
- //width: 560px;
+ width: 500px;
flex: 1 1 auto;
}
@@ -296,11 +208,8 @@
.error-text {
color: #c40233;
- width: 300;
- margin-left: -20;
font-size: 10;
margin-bottom: 4;
- margin-top: -3;
}
.success-text {
@@ -317,7 +226,6 @@
}
h1 {
- color: #121721;
text-transform: uppercase;
letter-spacing: 2px;
font-size: 19;
@@ -346,7 +254,6 @@
.padding {
padding: 0 0 0 20px;
- color: black;
}
}
}
@@ -357,21 +264,19 @@
min-height: 250px;
height: 100%;
width: 100%;
-
- .settings-content {
- background-color: $off-white;
- }
}
.settings-panel {
position: relative;
min-width: 150px;
- background-color: $light-blue;
.settings-user {
position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
bottom: 10px;
- text-align: center;
left: 0;
right: 0;
@@ -388,16 +293,11 @@
.settings-tabs {
// font-size: 16px;
font-weight: 600;
- color: black;
.tab-control {
padding: 10px;
border-bottom: 1px solid #9f9e9e;
cursor: pointer;
-
- &.active {
- background-color: #fdfdfd;
- }
}
}
@@ -416,20 +316,31 @@
.tab-content {
display: flex;
+ flex-flow: row wrap;
+ gap: 10px;
+ overflow: hidden;
.tab-column {
- flex: 0 0 50%;
+ flex: 0 0 calc(50% - 10px);
+ flex-direction: column;
+ display: flex;
+ justify-content: flex-start;
+ align-items: flex-start;
.tab-column-title {
- color: black;
font-size: 16px;
font-weight: bold;
- margin-bottom: 16px;
+ margin-bottom: 10px;
}
.tab-column-title,
.tab-column-content {
- padding-left: 16px;
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ flex-direction: column;
+ gap: 10px;
+ width: 100%;
}
}
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index f886ce2ca..b6df5f26a 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -11,19 +11,23 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
import { MainViewModal } from '../views/MainViewModal';
-import { FontIconBox } from '../views/nodes/button/FontIconBox';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
import { DragManager } from './DragManager';
import { GroupManager } from './GroupManager';
import './SettingsManager.scss';
import { undoBatch } from './UndoManager';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
+import { BsGoogle } from 'react-icons/bs'
+import { FaFillDrip, FaPalette } from 'react-icons/fa'
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
export enum ColorScheme {
- Dark = '-Dark',
- Light = '-Light',
- System = '-MatchSystem',
+ Dark = 'Dark',
+ Light = 'Light',
+ System = 'Match System',
+ Custom = 'Custom'
}
export enum freeformScrollMode {
@@ -50,8 +54,8 @@ export class SettingsManager extends React.Component<{}> {
@computed get backgroundColor() {
return Doc.UserDoc().activeCollectionBackground;
}
- @computed get colorScheme() {
- return Doc.ActiveDashboard?.colorScheme;
+ @computed get userTheme() {
+ return Doc.UserDoc().userTheme;
}
constructor(props: {}) {
@@ -73,14 +77,31 @@ export class SettingsManager extends React.Component<{}> {
}
};
- @undoBatch selectUserMode = action((e: React.ChangeEvent) => (Doc.noviceMode = (e.currentTarget as any)?.value === 'Novice'));
+ @computed get userColor() {
+ return StrCast(Doc.UserDoc().userColor)
+ }
+
+ @computed get userVariantColor() {
+ return StrCast(Doc.UserDoc().userVariantColor)
+ }
+
+ @computed get userBackgroundColor() {
+ return StrCast(Doc.UserDoc().userBackgroundColor)
+ }
+
+ @undoBatch selectUserMode = action((mode: string) => (Doc.noviceMode = mode === 'Novice'));
@undoBatch changelayout_showTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().layout_showTitle = (e.currentTarget as any).value ? 'title' : undefined));
- @undoBatch changeFontFamily = action((e: React.ChangeEvent) => (Doc.UserDoc().fontFamily = (e.currentTarget as any).value));
- @undoBatch changeFontSize = action((e: React.ChangeEvent) => (Doc.UserDoc().fontSize = (e.currentTarget as any).value));
- @undoBatch switchActiveBackgroundColor = action((color: ColorState) => (Doc.UserDoc().activeCollectionBackground = String(color.hex)));
- @undoBatch switchUserColor = action((color: ColorState) => {
- Doc.SharingDoc().userColor = undefined;
- Doc.GetProto(Doc.SharingDoc()).userColor = String(color.hex);
+ @undoBatch changeFontFamily = action((font: string) => (Doc.UserDoc().fontFamily = font));
+ @undoBatch changeFontSize = action((val: number) => (Doc.UserDoc().fontSize = val));
+ @undoBatch switchUserBackgroundColor = action((color: string) => {
+ Doc.UserDoc().userBackgroundColor = color;
+ addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: `${color} !important` });
+ });
+ @undoBatch switchUserColor = action((color: string) => {
+ Doc.UserDoc().userColor = color;
+ });
+ @undoBatch switchUserVariantColor = action((color: string) => {
+ Doc.UserDoc().userVariantColor = color;
});
@undoBatch playgroundModeToggle = action(() => {
this.playgroundMode = !this.playgroundMode;
@@ -92,82 +113,59 @@ export class SettingsManager extends React.Component<{}> {
@undoBatch
@action
- changeColorScheme = action((e: React.ChangeEvent) => {
- const activeDashboard = Doc.ActiveDashboard;
- if (!activeDashboard) return;
- const scheme: ColorScheme = (e.currentTarget as any).value;
+ changeColorScheme = action((scheme: string) => {
+ Doc.UserDoc().userTheme = scheme;
switch (scheme) {
case ColorScheme.Light:
- activeDashboard.colorScheme = undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
- addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: '#d3d3d3 !important' });
+ this.switchUserColor("#323232")
+ this.switchUserBackgroundColor("#DFDFDF")
+ this.switchUserVariantColor("#BDDDF5")
break;
case ColorScheme.Dark:
- activeDashboard.colorScheme = ColorScheme.Dark;
- addStyleSheetRule(SettingsManager._settingsStyle, 'lm_header', { background: 'black !important' });
+ this.switchUserColor("#DFDFDF")
+ this.switchUserBackgroundColor("#323232")
+ this.switchUserVariantColor("#4476F7")
+ break;
+ case ColorScheme.Custom:
break;
case ColorScheme.System:
default:
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
- activeDashboard.colorScheme = e.matches ? ColorScheme.Dark : undefined; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
+ e.matches ? ColorScheme.Dark : ColorScheme.Light; // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
});
break;
}
});
@computed get colorsContent() {
- const colorBox = (func: (color: ColorState) => void) => (
- <SketchPicker
- onChange={func}
- color={StrCast(this.backgroundColor)}
- presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- />
- );
-
- const colorFlyout = (
- <div className="colorFlyout">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={colorBox(this.switchActiveBackgroundColor)}>
- <div className="colorFlyout-button" style={{ backgroundColor: StrCast(this.backgroundColor) }} onPointerDown={e => e.stopPropagation()}>
- <FontAwesomeIcon icon="palette" size="sm" color={StrCast(this.backgroundColor)} />
- </div>
- </Flyout>
- </div>
- );
- const userColorFlyout = (
- <div className="colorFlyout">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={colorBox(this.switchUserColor)}>
- <div className="colorFlyout-button" style={{ backgroundColor: StrCast(this.backgroundColor) }} onPointerDown={e => e.stopPropagation()}>
- <FontAwesomeIcon icon="palette" size="sm" color={StrCast(this.backgroundColor)} />
- </div>
- </Flyout>
- </div>
- );
- const colorSchemes = [ColorScheme.Light, ColorScheme.Dark, ColorScheme.System];
- const schemeMap = ['Light', 'Dark', 'Match system'];
+ const colorSchemes = [ColorScheme.Light, ColorScheme.Dark, ColorScheme.Custom, ColorScheme.System];
+ const schemeMap = ['Light', 'Dark', 'Custom', 'Match System'];
+ const userTheme = StrCast(Doc.UserDoc().userTheme);
return (
- <div className="colors-content">
- <div className="preferences-color">
- <div className="preferences-color-text">Background Color</div>
- {colorFlyout}
- </div>
- <div className="preferences-color">
- <div className="preferences-color-text">Border/Header Color</div>
- {userColorFlyout}
- </div>
- <div className="preferences-colorScheme">
- <div className="preferences-color-text">Color Scheme</div>
- <div className="preferences-color-controls">
- <select className="scheme-select" onChange={this.changeColorScheme} defaultValue={StrCast(Doc.ActiveDashboard?.colorScheme)}>
- {colorSchemes.map((scheme, i) => (
- <option key={scheme} value={scheme}>
- {' '}
- {schemeMap[i]}{' '}
- </option>
- ))}
- </select>
- </div>
- </div>
+ <div style={{width: '100%'}}>
+ <Dropdown
+ formLabel='Theme'
+ size={Size.SMALL}
+ type={Type.TERT}
+ selectedVal={userTheme}
+ setSelectedVal={(scheme) => this.changeColorScheme(scheme as string)}
+ items={colorSchemes.map((scheme, i) => (
+ {
+ text: schemeMap[i],
+ val: scheme
+ }
+ ))}
+ dropdownType={DropdownType.SELECT}
+ color={this.userColor}
+ fillWidth
+ />
+ {userTheme === ColorScheme.Custom && <Group formLabel='Custom Theme'>
+ <ColorPicker tooltip={'User Color'} color={this.userColor} type={Type.SEC} icon={<FaFillDrip/>} selectedColor={this.userColor} setSelectedColor={this.switchUserColor}/>
+ <ColorPicker tooltip={'User Background Color'} color={this.userColor} type={Type.SEC} icon={<FaPalette/>} selectedColor={this.userBackgroundColor} setSelectedColor={this.switchUserBackgroundColor}/>
+ <ColorPicker tooltip={'User Variant Color'} color={this.userColor} type={Type.SEC} icon={<FaPalette/>} selectedColor={this.userVariantColor} setSelectedColor={this.switchUserVariantColor}/>
+ </Group>}
</div>
);
}
@@ -175,30 +173,65 @@ export class SettingsManager extends React.Component<{}> {
@computed get formatsContent() {
return (
<div className="prefs-content">
- <div>
- <input type="checkbox" onChange={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')} checked={Doc.UserDoc().layout_showTitle !== undefined} />
- <div className="preferences-check">Show doc header</div>
- </div>
- <div>
- <input type="checkbox" onChange={e => (Doc.UserDoc()['documentLinksButton-fullMenu'] = !Doc.UserDoc()['documentLinksButton-fullMenu'])} checked={BoolCast(Doc.UserDoc()['documentLinksButton-fullMenu'])} />
- <div className="preferences-check">Show full toolbar</div>
- </div>
- <div>
- <input type="checkbox" onChange={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} checked={FontIconBox.GetShowLabels()} />
- <div className="preferences-check">Show button labels</div>
- </div>
- <div>
- <input type="checkbox" onChange={e => FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())} checked={FontIconBox.GetRecognizeGestures()} />
- <div className="preferences-check">Recognize ink Gestures</div>
- </div>
- <div>
- <input type="checkbox" onChange={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)} checked={BoolCast(Doc.UserDoc().activeInkHideTextLabels)} />
- <div className="preferences-check">Hide Labels In Ink Shapes</div>
- </div>
- <div>
- <input type="checkbox" onChange={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)} checked={BoolCast(Doc.UserDoc().openInkInLightbox)} />
- <div className="preferences-check">Open Ink Docs in Lightbox</div>
- </div>
+ <Toggle
+ formLabel={'Show document header'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')}
+ toggleStatus={Doc.UserDoc().layout_showTitle !== undefined} size={Size.XSMALL}
+ color={this.userColor}
+
+ />
+ <Toggle
+ formLabel={'Show Full Toolbar'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => (Doc.UserDoc()['documentLinksButton-fullMenu'] = !Doc.UserDoc()['documentLinksButton-fullMenu'])}
+ toggleStatus={BoolCast(Doc.UserDoc()['documentLinksButton-fullMenu'])}
+ size={Size.XSMALL}
+ color={this.userColor}
+
+ />
+ <Toggle
+ formLabel={'Show Button Labels'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())}
+ toggleStatus={FontIconBox.GetShowLabels()}
+ size={Size.XSMALL}
+ color={this.userColor}
+
+ />
+ <Toggle
+ formLabel={'Recognize Ink Gestures'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())}
+ toggleStatus={FontIconBox.GetRecognizeGestures()}
+ size={Size.XSMALL}
+ color={this.userColor}
+
+ />
+ <Toggle
+ formLabel={'Hide Labels In Ink Shapes'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)}
+ toggleStatus={BoolCast(Doc.UserDoc().activeInkHideTextLabels)}
+ size={Size.XSMALL}
+ color={this.userColor}
+
+ />
+ <Toggle
+ formLabel={'Open Ink Docs in Lightbox'}
+ formLabelPlacement={'right'}
+ toggleType={ToggleType.SWITCH}
+ onClick={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)}
+ toggleStatus={BoolCast(Doc.UserDoc().openInkInLightbox)}
+ size={Size.XSMALL}
+ color={this.userColor}
+
+ />
</div>
);
}
@@ -224,25 +257,38 @@ export class SettingsManager extends React.Component<{}> {
return (
<div className="tab-content appearances-content">
- <div className="preferences-font">
- <div className="preferences-font-text">Default Font</div>
- <div className="preferences-font-controls">
- <select className="size-select" onChange={this.changeFontSize} value={StrCast(Doc.UserDoc().fontSize, '7px')}>
- {fontSizes.map(size => (
- <option key={size} value={size} defaultValue={StrCast(Doc.UserDoc().fontSize)}>
- {' '}
- {size}{' '}
- </option>
- ))}
- </select>
- <select className="font-select" onChange={this.changeFontFamily} value={StrCast(Doc.UserDoc().fontFamily, 'Times New Roman')}>
- {fontFamilies.map(font => (
- <option key={font} value={font} defaultValue={StrCast(Doc.UserDoc().fontFamily)}>
- {' '}
- {font}{' '}
- </option>
- ))}
- </select>
+ <div className="tab-column">
+ <div className="tab-column-title">Text</div>
+ <div className="tab-column-content">
+ {/* <NumberInput/> */}
+ <Group formLabel={'Default Font'}>
+ <NumberDropdown
+ color={this.userColor}
+ numberDropdownType={'input'}
+ min={0} max={50} step={2}
+ type={Type.TERT}
+ number={0}
+ unit={"px"}
+ setNumber={() => {}}
+ />
+ <Dropdown
+ items={fontFamilies.map((val) => {
+ return {
+ text: val,
+ val: val,
+ style: {
+ fontFamily: val
+ }
+ }
+ })}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ selectedVal={StrCast(Doc.UserDoc().fontFamily)}
+ setSelectedVal={(val) => {this.changeFontFamily(val as string)}}
+ color={this.userColor}
+ fillWidth
+ />
+ </Group>
</div>
</div>
</div>
@@ -250,8 +296,7 @@ export class SettingsManager extends React.Component<{}> {
}
@action
- changeVal = (e: React.ChangeEvent, pass: string) => {
- const value = (e.target as any).value;
+ changeVal = (value: string, pass: string) => {
switch (pass) {
case 'curr':
this.curr_password = value;
@@ -268,20 +313,33 @@ export class SettingsManager extends React.Component<{}> {
@computed get passwordContent() {
return (
<div className="password-content">
- <div className="password-content-inputs">
- <input className="password-inputs" type="password" placeholder="current password" onChange={e => this.changeVal(e, 'curr')} />
- <input className="password-inputs" type="password" placeholder="new password" onChange={e => this.changeVal(e, 'new')} />
- <input className="password-inputs" type="password" placeholder="confirm new password" onChange={e => this.changeVal(e, 'conf')} />
- </div>
- <div className="password-content-buttons">
- {!this.passwordResultText ? null : <div className={`${this.passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this.passwordResultText}</div>}
- <a className="password-forgot" href="/forgotPassword">
- forgot password?
- </a>
- <button className="password-submit" onClick={this.changePassword}>
- submit
- </button>
- </div>
+ <EditableText placeholder="Current password"
+ type={Type.SEC}
+ color={this.userColor}
+ val={""}
+ setVal={val => this.changeVal(val as string, 'curr')}
+ fillWidth
+ password
+ />
+ <EditableText placeholder="New password"
+ type={Type.SEC}
+ color={this.userColor}
+ val={""}
+ setVal={val => this.changeVal(val as string, 'new')}
+ fillWidth
+ password
+ />
+ <EditableText placeholder="Confirm new password"
+ type={Type.SEC}
+ color={this.userColor}
+ val={""}
+ setVal={val => this.changeVal(val as string, 'conf')}
+ fillWidth
+ password
+ />
+ {!this.passwordResultText ? null : <div className={`${this.passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this.passwordResultText}</div>}
+ <Button type={Type.SEC} text={'Forgot Password'} color={this.userColor}/>
+ <Button type={Type.TERT} text={'Submit'} onClick={this.changePassword} color={this.userColor}/>
</div>
);
}
@@ -289,9 +347,7 @@ export class SettingsManager extends React.Component<{}> {
@computed get accountOthersContent() {
return (
<div className="account-others-content">
- <button onClick={this.googleAuthorize} value="data">
- Authorize Google Acc
- </button>
+ <Button type={Type.TERT} text={'Connect to Google'} iconPlacement='left' icon={<BsGoogle/>} onClick={() => this.googleAuthorize()}/>
</div>
);
}
@@ -311,7 +367,7 @@ export class SettingsManager extends React.Component<{}> {
);
}
- setFreeformScrollMode = (mode: freeformScrollMode) => {
+ setFreeformScrollMode = (mode: string) => {
Doc.UserDoc().freeformScrollMode = mode;
};
@@ -321,45 +377,78 @@ export class SettingsManager extends React.Component<{}> {
<div className="tab-column">
<div className="tab-column-title">Modes</div>
<div className="tab-column-content">
- <select className="modes-select" onChange={this.selectUserMode} defaultValue={Doc.noviceMode ? 'Novice' : 'Developer'}>
- <option key={'Novice'} value={'Novice'}>
- {' '}
- Novice{' '}
- </option>
- <option key={'Developer'} value={'Developer'}>
- {' '}
- Developer
- </option>
- </select>
- <div className="modes-playground">
- <input className="playground-check" type="checkbox" checked={this.playgroundMode} onChange={this.playgroundModeToggle} />
- <div className="playground-text">Playground Mode</div>
- </div>
+ <Dropdown
+ formLabel={"Mode"}
+ items={[
+ {
+ text: 'Novice',
+ description: 'Novice mode is a user-friendly setting designed to cater to those who are new to Dash',
+ val: "Novice"
+ },
+ {
+ text: 'Developer',
+ description: 'Developer mode is an advanced setting that grants you greater control and access to the underlying mechanics and tools of a software or system. Developer mode is still under development as there are experimental features.',
+ val: "Developer"
+ },
+ ]}
+ selectedVal={Doc.noviceMode ? 'Novice' : 'Developer'}
+ setSelectedVal={(val) => {this.selectUserMode(val as string)}}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ placement='bottom-start'
+ color={this.userColor}
+ fillWidth
+ />
+ <Toggle
+ formLabel={'Playground Mode'}
+ toggleType={ToggleType.SWITCH}
+ toggleStatus={this.playgroundMode}
+ onClick={this.playgroundModeToggle}
+ color={this.userColor}
+ />
</div>
- <div className="tab-column-title" style={{ marginTop: 10, marginBottom: 0 }}>
- Freeform scrolling
+ <div className="tab-column-title" style={{ marginTop: 20, marginBottom: 10 }}>
+ Freeform Navigation
</div>
<div className="tab-column-content">
- <button style={{ backgroundColor: Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? 'blue' : '' }} onClick={() => this.setFreeformScrollMode(freeformScrollMode.Pan)}>
- Scroll to pan
- </button>
- <div>
- <div>Scrolling pans canvas, shift + scrolling zooms</div>
- </div>
- <button style={{ backgroundColor: Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom ? 'blue' : '' }} onClick={() => this.setFreeformScrollMode(freeformScrollMode.Zoom)}>
- Scroll to zoom
- </button>
- <div>Scrolling zooms canvas</div>
+ <Dropdown
+ formLabel={"Scroll Mode"}
+ items={[
+ {
+ text: 'Scroll to Pan',
+ description: 'Scrolling pans canvas, shift + scrolling zooms',
+ val: freeformScrollMode.Pan
+ },
+ {
+ text: 'Scroll to Zoom',
+ description: 'Scrolling zooms canvas',
+ val: freeformScrollMode.Zoom
+ },
+ ]}
+ selectedVal={StrCast(Doc.UserDoc().freeformScrollMode)}
+ setSelectedVal={(val) => this.setFreeformScrollMode(val as string)}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ placement='bottom-start'
+ color={this.userColor}
+ />
</div>
</div>
<div className="tab-column">
<div className="tab-column-title">Permissions</div>
<div className="tab-column-content">
- <button onClick={() => GroupManager.Instance?.open()}>Manage groups</button>
- <div className="default-acl">
- <input className="acl-check" type="checkbox" checked={BoolCast(Doc.defaultAclPrivate)} onChange={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))} />
- <div className="acl-text">Default access private</div>
- </div>
+ <Button
+ text={"Manage Groups"}
+ type={Type.TERT}
+ onClick={() => GroupManager.Instance?.open()}
+ color={this.userColor}
+ />
+ <Toggle
+ toggleType={ToggleType.SWITCH}
+ formLabel={"Default access private"}
+ color={this.userColor}
+ toggleStatus={BoolCast(Doc.defaultAclPrivate)}
+ onClick={action(() => (Doc.defaultAclPrivate = !Doc.defaultAclPrivate))}/>
</div>
</div>
</div>
@@ -376,31 +465,50 @@ export class SettingsManager extends React.Component<{}> {
{ title: 'Appearance', ele: this.appearanceContent },
{ title: 'Text', ele: this.textContent },
];
-
return (
<div className="settings-interface">
- <div className="settings-panel">
+ <div className="settings-panel" style={{ background: this.userColor }}>
<div className="settings-tabs">
- {tabs.map(tab => (
- <div key={tab.title} className={'tab-control ' + (this.activeTab === tab.title ? 'active' : 'inactive')} onClick={action(() => (this.activeTab = tab.title))}>
- {tab.title}
- </div>
- ))}
+ {tabs.map(tab => {
+ const isActive = this.activeTab === tab.title
+ return (
+ <div key={tab.title}
+ style={{
+ background: isActive ? this.userBackgroundColor : this.userColor,
+ color: isActive ? this.userColor : this.userBackgroundColor,
+ }}
+ className={'tab-control ' + (isActive ? 'active' : 'inactive')}
+ onClick={action(() => (this.activeTab = tab.title))
+ }>
+ {tab.title}
+ </div>
+ )
+ })}
</div>
<div className="settings-user">
- <div className="settings-username">{Doc.CurrentUserEmail}</div>
- <button className="logout-button" onClick={() => window.location.assign(Utils.prepend('/logout'))}>
- {Doc.GuestDashboard ? 'Exit' : 'Log Out'}
- </button>
+ <div className="settings-username"
+ style={{color: this.userBackgroundColor}}
+ >{Doc.CurrentUserEmail}</div>
+ <Button
+ text={Doc.GuestDashboard ? 'Exit' : 'Log Out'}
+ type={Type.TERT}
+ color={this.userVariantColor}
+ onClick={() => window.location.assign(Utils.prepend('/logout'))}
+ />
</div>
</div>
- <div className="close-button" onClick={this.close}>
- <FontAwesomeIcon icon={'times'} color="black" size={'lg'} />
+
+ <div className="close-button">
+ <Button
+ icon={<FontAwesomeIcon icon={'times'} size={'lg'} />}
+ onClick={this.close}
+ color={this.userColor}
+ />
</div>
- <div className="settings-content">
+ <div className="settings-content" style={{color: this.userColor, background: this.userBackgroundColor}}>
{tabs.map(tab => (
<div key={tab.title} className={'tab-section ' + (this.activeTab === tab.title ? 'active' : 'inactive')}>
{tab.ele}
@@ -418,7 +526,7 @@ export class SettingsManager extends React.Component<{}> {
isDisplayed={this.isOpen}
interactive={true}
closeOnExternalClick={this.close}
- dialogueBoxStyle={{ width: '500px', height: '300px', background: Cast(Doc.SharingDoc().userColor, 'string', null) }}
+ dialogueBoxStyle={{ width: 'fit-content', height: '300px', background: Cast(Doc.UserDoc().userColor, 'string', null) }}
/>
);
}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index 6c4612dc8..05401e2cd 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -17,10 +17,8 @@
.close-button {
position: absolute;
- right: 1em;
- top: 1em;
- cursor: pointer;
- z-index: 999;
+ right: 2px;
+ top: 2px;
}
.share-title {