diff options
Diffstat (limited to 'src/client/util')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 31 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 4 | ||||
-rw-r--r-- | src/client/util/LinkFollower.ts | 25 | ||||
-rw-r--r-- | src/client/util/ServerStats.tsx | 4 | ||||
-rw-r--r-- | src/client/util/SettingsManager.tsx | 43 |
5 files changed, 59 insertions, 48 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 452bb74cd..2ea5972ee 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -8,10 +8,10 @@ import { RichTextField } from "../../fields/RichTextField"; import { listSpec } from "../../fields/Schema"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, DateCast, DocCast, StrCast } from "../../fields/Types"; -import { nullAudio, URLField, WebField } from "../../fields/URLField"; +import { nullAudio, WebField } from "../../fields/URLField"; import { SetCachedGroups, SharingPermissions } from "../../fields/util"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; -import { addStyleSheetRule, OmitKeys, Utils } from "../../Utils"; +import { OmitKeys, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents"; import { CollectionViewType, DocumentType } from "../documents/DocumentTypes"; @@ -19,7 +19,7 @@ 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 { DocumentView, OpenWhere } from "../views/nodes/DocumentView"; import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox"; import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox"; import { OverlayView } from "../views/OverlayView"; @@ -28,7 +28,7 @@ import { MakeTemplate } from "./DropConverter"; import { FollowLinkScript } from "./LinkFollower"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; -import { ColorScheme, SettingsManager } from "./SettingsManager"; +import { ColorScheme } from "./SettingsManager"; import { UndoManager } from "./UndoManager"; interface Button { @@ -476,7 +476,6 @@ export class CurrentUserUtils { static setupDashboards(doc: Doc, field:string) { var myDashboards = DocCast(doc[field]); - const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`; const newDashboard = `createNewDashboard()`; const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, @@ -487,14 +486,14 @@ export class CurrentUserUtils { const contextMenuScripts = [/*newDashboard*/] as string[]; const contextMenuLabels = [/*"Create New Dashboard"*/] as string[]; const contextMenuIcons = [/*"plus"*/] as string[]; - const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)', 'resetDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters - const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any, '!IsNoviceMode()'];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts - const childContextMenuLabels = ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters - const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters + const childContextMenuScripts = [`toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)', 'resetDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters + const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any, '!IsNoviceMode()'];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts + const childContextMenuLabels = ["Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters + const childContextMenuIcons = ["tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { title: "My Dashboards", childHideLinkButton: true, treeView_FreezeChildren: "remove|add", treeView_HideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - dropAction: "same", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, - layout_headerButton: newDashboardButton, childDragAction: "none", + dropAction: "inSame", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, + layout_headerButton: newDashboardButton, childDragAction: "inSame", _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List<string>(contextMenuLabels), contextMenuIcons:new List<string>(contextMenuIcons), @@ -708,14 +707,14 @@ export class CurrentUserUtils { 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: 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: "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: "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: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, 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: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available @@ -892,7 +891,6 @@ export class CurrentUserUtils { 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); @@ -920,10 +918,6 @@ export class CurrentUserUtils { Doc.GetProto(DocCast(Doc.UserDoc().emptyWebpage)).data = new WebField("https://www.wikipedia.org") - if (doc.activeDashboard instanceof Doc) { - // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) - doc.activeDashboard.colorScheme = doc.activeDashboard.colorScheme === ColorScheme.Light ? undefined : doc.activeDashboard.colorScheme; - } new LinkManager(); DocServer.CacheNeedsUpdate && setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500); @@ -1028,6 +1022,7 @@ export class CurrentUserUtils { } ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "document containing all shared Docs"); +ScriptingGlobals.add(function IsExploreMode() { return DocumentView.ExploreMode; }, "is Dash in exploration mode"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 6d6eaebec..f86f9a3e5 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -14,7 +14,7 @@ import { SelectionManager } from './SelectionManager'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; -export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove +export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove /** * Initialize drag @@ -324,7 +324,7 @@ export namespace DragManager { export let CanEmbed = false; export let DocDragData: DocumentDragData | undefined; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void, dragUndoName?: string) { - if (dragData.dropAction === 'none') return; + if (dragData.dropAction === 'none' || DocumentView.ExploreMode) return; DocDragData = dragData as DocumentDragData; const batch = UndoManager.StartBatch(dragUndoName ?? 'document drag'); eles = eles.filter(e => e); diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 2fc811b09..146eed6c2 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -68,22 +68,23 @@ export class LinkFollower { ? linkDoc.link_anchor_2 : linkDoc.link_anchor_1 ) as Doc; + const srcAnchor = LinkManager.getOppositeAnchor(linkDoc, target) ?? sourceDoc; if (target) { const doFollow = (canToggle?: boolean) => { const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle); const options: DocFocusOptions = { - playAudio: BoolCast(sourceDoc.followLinkAudio), - playMedia: BoolCast(sourceDoc.followLinkVideo), + playAudio: BoolCast(srcAnchor.followLinkAudio), + playMedia: BoolCast(srcAnchor.followLinkVideo), toggleTarget, noSelect: true, willPan: true, - willZoomCentered: BoolCast(sourceDoc.followLinkZoom, false), - zoomTime: NumCast(sourceDoc.followLinkTransitionTime, 500), - zoomScale: Cast(sourceDoc.followLinkZoomScale, 'number', null), - easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, - openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox) as OpenWhere, - effect: sourceDoc, - zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), + willZoomCentered: BoolCast(srcAnchor.followLinkZoom, false), + zoomTime: NumCast(srcAnchor.followLinkTransitionTime, 500), + zoomScale: Cast(srcAnchor.followLinkZoomScale, 'number', null), + easeFunc: StrCast(srcAnchor.followLinkEase, 'ease') as any, + openLocation: StrCast(srcAnchor.followLinkLocation, OpenWhere.lightbox) as OpenWhere, + effect: srcAnchor, + zoomTextSelections: BoolCast(srcAnchor.followLinkZoomText), }; if (target.type === DocumentType.PRES) { const containerDocContext = DocumentManager.GetContextPath(sourceDoc, true); // gather all views that affect layout of sourceDoc so we can revert them after playing the rail @@ -97,7 +98,7 @@ export class LinkFollower { } }; let movedTarget = false; - if (sourceDoc.followLinkLocation === OpenWhere.inParent) { + if (srcAnchor.followLinkLocation === OpenWhere.inParent) { const sourceDocParent = DocCast(sourceDoc.embedContainer); if (target.embedContainer instanceof Doc && target.embedContainer !== sourceDocParent) { Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutFieldKey(target.embedContainer), target); @@ -109,11 +110,11 @@ export class LinkFollower { } Doc.SetContainer(target, sourceDocParent); const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)]; - if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) { + if (srcAnchor.followLinkXoffset !== undefined && moveTo[0] !== target.x) { target.x = moveTo[0]; movedTarget = true; } - if (sourceDoc.followLinkYoffset !== undefined && moveTo[1] !== target.y) { + if (srcAnchor.followLinkYoffset !== undefined && moveTo[1] !== target.y) { target.y = moveTo[1]; movedTarget = true; } diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx index ac9fecd5c..08dbaac5d 100644 --- a/src/client/util/ServerStats.tsx +++ b/src/client/util/ServerStats.tsx @@ -46,12 +46,12 @@ export class ServerStats extends React.Component<{}> { <div style={{ display: 'flex', - height: 300, + height: '100%', width: 400, background: SettingsManager.userBackgroundColor, opacity: 0.6, }}> - <div style={{ width: 300, height: 100, margin: 'auto', display: 'flex', flexDirection: 'column' }}> + <div style={{ width: 300, margin: 'auto', display: 'flex', flexDirection: 'column' }}> {PingManager.Instance.IsBeating ? 'The server connection is active' : 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'} <br /> diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 085ff4bb1..dc852596f 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -20,10 +20,9 @@ import { undoBatch } from './UndoManager'; export enum ColorScheme { Dark = 'Dark', Light = 'Light', - CoolBlue = 'Cool Blue', - Cupcake = 'Cupcake', - System = 'Match System', Custom = 'Custom', + CoolBlue = 'CoolBlue', + Cupcake = 'Cupcake', } export enum freeformScrollMode { @@ -50,7 +49,21 @@ export class SettingsManager extends React.Component<{}> { constructor(props: {}) { super(props); SettingsManager.Instance = this; + this.matchSystem(); + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { + if (Doc.UserDoc().userThemeSystem) { + if (window.matchMedia('(prefers-color-scheme: dark)').matches) this.changeColorScheme(ColorScheme.Dark); + if (window.matchMedia('(prefers-color-scheme: light)').matches) this.changeColorScheme(ColorScheme.Light); + } + // undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss) + }); } + matchSystem = () => { + if (Doc.UserDoc().userThemeSystem) { + if (window.matchMedia('(prefers-color-scheme: dark)').matches) this.changeColorScheme(ColorScheme.Dark); + if (window.matchMedia('(prefers-color-scheme: light)').matches) this.changeColorScheme(ColorScheme.Light); + } + }; public close = action(() => (this.isOpen = false)); public open = action(() => (this.isOpen = true)); @@ -88,6 +101,10 @@ export class SettingsManager extends React.Component<{}> { }); @undoBatch switchUserColor = action((color: string) => (Doc.UserDoc().userColor = color)); @undoBatch switchUserVariantColor = action((color: string) => (Doc.UserDoc().userVariantColor = color)); + @undoBatch userThemeSystemToggle = action(() => { + Doc.UserDoc().userThemeSystem = !Doc.UserDoc().userThemeSystem; + this.matchSystem(); + }); @undoBatch playgroundModeToggle = action(() => { this.playgroundMode = !this.playgroundMode; if (this.playgroundMode) { @@ -123,18 +140,11 @@ export class SettingsManager extends React.Component<{}> { break; case ColorScheme.Custom: break; - case ColorScheme.System: - default: - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { - 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 colorSchemes = [ColorScheme.Light, ColorScheme.Dark, ColorScheme.Cupcake, ColorScheme.CoolBlue, ColorScheme.Custom, ColorScheme.System]; - const schemeMap = ['Light', 'Dark', 'Cupcake', 'Cool Blue', 'Custom', 'Match System']; + const schemeMap = Array.from(Object.keys(ColorScheme)); const userTheme = StrCast(Doc.UserDoc().userTheme); return ( <div style={{ width: '100%' }}> @@ -144,15 +154,20 @@ export class SettingsManager extends React.Component<{}> { type={Type.TERT} closeOnSelect={false} selectedVal={userTheme} - setSelectedVal={scheme => this.changeColorScheme(scheme as string)} - items={colorSchemes.map((scheme, i) => ({ - text: schemeMap[i], + setSelectedVal={scheme => { + this.changeColorScheme(scheme as string); + Doc.UserDoc().userThemeSystem = false; + }} + items={Object.keys(ColorScheme).map((scheme, i) => ({ + text: schemeMap[i].replace(/([a-z])([A-Z])/, '$1 $2'), val: scheme, }))} dropdownType={DropdownType.SELECT} color={SettingsManager.userColor} fillWidth /> + <Toggle formLabel="Match System" toggleType={ToggleType.SWITCH} color={SettingsManager.userColor} toggleStatus={BoolCast(Doc.UserDoc().userThemeSystem)} onClick={this.userThemeSystemToggle} /> + {userTheme === ColorScheme.Custom && ( <Group formLabel="Custom Theme"> <ColorPicker |