aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deploy/mobile/image.html5
-rw-r--r--package-lock.json84
-rw-r--r--src/client/util/CurrentUserUtils.ts104
-rw-r--r--src/client/util/SettingsManager.scss31
-rw-r--r--src/client/views/AntimodeMenu.scss46
-rw-r--r--src/client/views/GestureOverlay.scss2
-rw-r--r--src/client/views/GestureOverlay.tsx4
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.scss14
-rw-r--r--src/client/views/collections/CollectionView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss39
-rw-r--r--src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx18
-rw-r--r--src/client/views/nodes/AudioBox.scss206
-rw-r--r--src/client/views/nodes/ColorBox.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx10
-rw-r--r--src/client/views/nodes/PresBox.scss65
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss283
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
-rw-r--r--src/client/views/presentationview/PresElementBox.scss97
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx2
-rw-r--r--src/mobile/ImageUpload.scss124
-rw-r--r--src/mobile/ImageUpload.tsx248
-rw-r--r--src/mobile/MobileHome.scss101
-rw-r--r--src/mobile/MobileInkOverlay.tsx4
-rw-r--r--src/mobile/MobileInterface.scss17
-rw-r--r--src/mobile/MobileInterface.tsx798
-rw-r--r--src/mobile/MobileMain.tsx25
-rw-r--r--src/mobile/MobileMenu.scss409
-rw-r--r--src/server/index.ts1
-rw-r--r--webpack.config.js64
33 files changed, 2330 insertions, 505 deletions
diff --git a/deploy/mobile/image.html b/deploy/mobile/image.html
index 6424d2a60..d30ad6ac2 100644
--- a/deploy/mobile/image.html
+++ b/deploy/mobile/image.html
@@ -1,15 +1,14 @@
<html>
<head>
- <title>Test view</title>
+ <title>Dash Mobile</title>
<link href="https://fonts.googleapis.com/css?family=Fjalla+One|Hind+Siliguri:300" rel="stylesheet">
</head>
<body>
<div id="root">
- <p>Capture Image: <input type="file" accept="image/*" id="capture">
</div>
- <script src="../imageUpload.js"></script>
+ <script src="../mobileInterface.js"></script>
</body>
</html> \ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 457104c8e..e692b266d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2841,7 +2841,8 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -2859,11 +2860,13 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -2876,15 +2879,18 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -2987,7 +2993,8 @@
},
"inherits": {
"version": "2.0.4",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -2997,6 +3004,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -3009,17 +3017,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -3036,6 +3047,7 @@
"mkdirp": {
"version": "0.5.3",
"bundled": true,
+ "optional": true,
"requires": {
"minimist": "^1.2.5"
}
@@ -3091,7 +3103,8 @@
},
"npm-normalize-package-bin": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"npm-packlist": {
"version": "1.4.8",
@@ -3116,7 +3129,8 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -3126,6 +3140,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3194,7 +3209,8 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -3224,6 +3240,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -3241,6 +3258,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -3279,11 +3297,13 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
}
}
}
@@ -9515,7 +9535,7 @@
},
"chownr": {
"version": "1.1.4",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "resolved": false,
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"ci-info": {
@@ -9821,7 +9841,7 @@
},
"deep-extend": {
"version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "resolved": false,
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"defaults": {
@@ -10320,7 +10340,7 @@
},
"glob": {
"version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "resolved": false,
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
@@ -10408,7 +10428,7 @@
},
"hosted-git-info": {
"version": "2.8.8",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+ "resolved": false,
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
},
"http-cache-semantics": {
@@ -10544,7 +10564,7 @@
},
"is-ci": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
+ "resolved": false,
"integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
"requires": {
"ci-info": "^1.5.0"
@@ -10620,7 +10640,7 @@
},
"is-retry-allowed": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
},
"is-stream": {
@@ -11129,7 +11149,7 @@
},
"mkdirp": {
"version": "0.5.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
+ "resolved": false,
"integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
"requires": {
"minimist": "^1.2.5"
@@ -11137,7 +11157,7 @@
"dependencies": {
"minimist": {
"version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "resolved": false,
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
@@ -11189,7 +11209,7 @@
},
"node-gyp": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==",
"requires": {
"env-paths": "^2.2.0",
@@ -11303,7 +11323,7 @@
},
"npm-packlist": {
"version": "1.4.8",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
+ "resolved": false,
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
"requires": {
"ignore-walk": "^3.0.1",
@@ -11323,7 +11343,7 @@
},
"npm-profile": {
"version": "4.0.4",
- "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz",
+ "resolved": false,
"integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==",
"requires": {
"aproba": "^1.1.2 || 2",
@@ -11333,7 +11353,7 @@
},
"npm-registry-fetch": {
"version": "4.0.3",
- "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz",
+ "resolved": false,
"integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==",
"requires": {
"JSONStream": "^1.3.4",
@@ -11768,7 +11788,7 @@
},
"rc": {
"version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "resolved": false,
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"requires": {
"deep-extend": "^0.6.0",
@@ -11779,7 +11799,7 @@
"dependencies": {
"minimist": {
"version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "resolved": false,
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
@@ -11838,7 +11858,7 @@
},
"readable-stream": {
"version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "resolved": false,
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
@@ -11859,7 +11879,7 @@
},
"registry-auth-token": {
"version": "3.4.0",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
+ "resolved": false,
"integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
"requires": {
"rc": "^1.1.6",
@@ -11923,7 +11943,7 @@
},
"rimraf": {
"version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "resolved": false,
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
@@ -12222,7 +12242,7 @@
},
"string_decoder": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "resolved": false,
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
@@ -12230,7 +12250,7 @@
"dependencies": {
"safe-buffer": {
"version": "5.2.0",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "resolved": false,
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
}
}
@@ -12542,7 +12562,7 @@
},
"widest-line": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
+ "resolved": false,
"integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
"requires": {
"string-width": "^2.1.1"
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 47672f7c9..323e398be 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -31,6 +31,7 @@ export class CurrentUserUtils {
public static get MainDocId() { return this.mainDocId; }
public static set MainDocId(id: string | undefined) { this.mainDocId = id; }
@computed public static get UserDocument() { return Doc.UserDoc(); }
+ @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; }
@observable public static GuestTarget: Doc | undefined;
@observable public static GuestWorkspace: Doc | undefined;
@@ -164,6 +165,16 @@ export class CurrentUserUtils {
});
}
+ // if (doc["mobile-button"] === undefined) {
+ // const mobileTemplate = this.mobileButton({ title: "mobile button", _backgroundColor: "lightgrey" }, [this.ficon({ ignoreClick: true, icon: "mobile", backgroundColor: "rgba(0,0,0,0)" }), this.mobileTextContainer({}, [this.mobileButtonText({}, "text"), this.mobileButtonInfo({}, "This is a default mobile button for use in the mobile menu")])]);
+ // mobileTemplate.isTemplateDoc = makeTemplate(mobileTemplate);
+ // doc["mobile-button"] = CurrentUserUtils.ficon({
+ // onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+ // dragFactory: new PrefetchProxy(mobileTemplate) as any as Doc,
+ // removeDropProperties: new List<string>(["dropAction"]), title: "mobile button view", icon: "mobile"
+ // });
+ // }
+
if (doc["template-button-detail"] === undefined) {
const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create;
@@ -367,6 +378,10 @@ export class CurrentUserUtils {
if (doc.emptyWebpage === undefined) {
doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 600, UseCors: true });
}
+ if (doc.activeMobile === undefined) {
+ console.log("phone setup");
+ this.setupActiveMobile(doc);
+ }
return [
{ title: "Drag a comparison box", label: "Comp", icon: "columns", ignoreClick: true, drag: 'Docs.Create.ComparisonDocument()' },
{ title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc },
@@ -380,7 +395,7 @@ export class CurrentUserUtils {
{ title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
{ title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' },
{ title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
- { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' },
+ { title: "Drag a mobile view", label: "Phone", icon: "mobile", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.activeMobile as Doc },
{ title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' },
// { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
// { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
@@ -434,25 +449,56 @@ export class CurrentUserUtils {
return doc.myItemCreators as Doc;
}
- static setupMobileButtons(doc: Doc, buttons?: string[]) {
- const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
- { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" },
- { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
- { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
- { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "pink", activeInkPen: doc },
- { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc },
- // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "red", activeInkPen: doc },
- { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" },
- // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
- ];
- return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick,
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activeInkPen: data.activeInkPen,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
+ static setupActiveMobile(doc: Doc) {
+ if (doc.activeMobile === undefined) {
+ console.log("undefined");
+ doc.activeMobile = this.setupMobileMenu();
+ }
+ return doc.activeMobile as Doc;
+ }
+
+ static setupMobileMenu() {
+ const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), {
+ _width: 980, ignoreClick: true, lockedPosition: false, _chromeStatus: "disabled", title: "home", _yMargin: 100
}));
+ return menu;
}
+ static setupMobileButtons(doc?: Doc, buttons?: string[]) {
+ const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, info: string, dragFactory?: Doc }[] = [
+ { title: "LIBRARY", icon: "bars", click: 'switchToLibrary()', backgroundColor: "#ffd6d6", info: "Navigate and access all of your documents within their respective collections" },
+ { title: "RECORD", icon: "microphone", click: 'openMobileAudio()', backgroundColor: "#ffbfbf", info: "Use your mobile to record audio and access it on Dash Web." },
+ { title: "UPLOAD", icon: "upload", click: 'uploadImageMobile()', backgroundColor: "#ff9e9e", info: "Upload an image from your mobile device so it can be accessed on Dash Web" },
+ { title: "PRESENTATION", icon: "desktop", click: 'openMobilePresentation()', backgroundColor: "#ff8080", info: "Use your phone as a remote for you presentation." },
+ { title: "SETTINGS", icon: "cog", click: 'openMobileSettings()', backgroundColor: "#ff5e5e", info: "Change your password, log out, or manage your account security" }
+ ];
+ return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => this.mobileButton({ title: data.title, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, _backgroundColor: data.backgroundColor }, [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)" }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])]));
+ }
+
+ static mobileButton = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.MulticolumnDocument(docs, {
+ ...opts,
+ dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
+ borderRounding: "5px", boxShadow: "0 0", _chromeStatus: "disabled",
+ })) as any as Doc
+
+ static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.MultirowDocument(docs, {
+ ...opts,
+ dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
+ backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", _chromeStatus: "disabled", ignoreClick: true
+ })) as any as Doc
+
+
+ static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => new PrefetchProxy(Docs.Create.TextDocument(buttonTitle, {
+ ...opts,
+ dropAction: undefined, title: buttonTitle, _fontSize: 37, _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)"
+ })) as any as Doc
+
+ static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => new PrefetchProxy(Docs.Create.TextDocument(buttonInfo, {
+ ...opts,
+ dropAction: undefined, title: "info", _fontSize: 25, _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2,
+ })) as any as Doc
+
+
static setupThumbButtons(doc: Doc) {
const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
{ title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
@@ -486,10 +532,8 @@ export class CurrentUserUtils {
return Cast(userDoc.thumbDoc, Doc);
}
- static setupMobileDoc(userDoc: Doc) {
- return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
- columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5
- });
+ static setupLibrary(userDoc: Doc) {
+ return CurrentUserUtils.setupWorkspaces(userDoc);
}
static setupMobileInkingDoc(userDoc: Doc) {
@@ -509,8 +553,8 @@ export class CurrentUserUtils {
});
}
- // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
- // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
+ // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
+ // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) {
// setup a masonry view of all he creators
const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
@@ -603,7 +647,7 @@ export class CurrentUserUtils {
return doc["tabs-button-library"] as Doc;
}
- // setup the Search button which will display the search panel.
+ // setup the Search button which will display the search panel.
static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) {
if (doc["tabs-button-search"] === undefined) {
doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
@@ -695,10 +739,11 @@ export class CurrentUserUtils {
static setupRightSidebar(doc: Doc) {
if (doc.rightSidebarCollection === undefined) {
- doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" }));
+ doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Mobile Uploads" }));
}
}
+
static setupClickEditorTemplates(doc: Doc) {
if (doc["clickFuncs-child"] === undefined) {
const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
@@ -744,13 +789,14 @@ export class CurrentUserUtils {
doc.activeInkWidth = StrCast(doc.activeInkWidth, "1");
doc.activeInkBezier = StrCast(doc.activeInkBezier, "");
doc.fontSize = NumCast(doc.fontSize, 12);
- doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); //
- doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); //
+ doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); //
+ doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); //
Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]);
this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
this.setupDocTemplates(doc); // sets up the template menu of templates
this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
- this.setupOverlays(doc); // documents in overlay layer
+ this.setupActiveMobile(doc);
+ this.setupOverlays(doc); // documents in overlay layer
this.setupDockedButtons(doc); // the bottom bar of font icons
this.setupDefaultPresentation(doc); // presentation that's initially triggered
await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels
@@ -789,4 +835,4 @@ export class CurrentUserUtils {
Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); });
Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); });
-Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file
+Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); });
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index 6513cb223..1eac9303b 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -133,4 +133,35 @@
}
+}
+
+@media only screen and (max-width: 1000px) {
+ .settings-interface {
+ background-color: whitesmoke !important;
+ color: grey;
+ width: 80vw;
+ height: 400px;
+ }
+
+ .settings-interface .settings-body .settings-content input {
+ border-radius: 5px;
+ border: none;
+ font-size: 30;
+ padding: 4px;
+ min-width: 100%;
+ margin: 2px 0;
+ }
+
+ .settings-interface button {
+ width: 100%;
+ font-size: 30px;
+ align-self: center;
+ background: #b2cef8;
+ margin-top: 4px;
+ }
+
+ .settings-interface .settings-heading {
+ letter-spacing: .5em;
+ font-size: 25;
+ }
} \ No newline at end of file
diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss
index d4a76ee17..170631422 100644
--- a/src/client/views/AntimodeMenu.scss
+++ b/src/client/views/AntimodeMenu.scss
@@ -39,4 +39,50 @@
background-repeat: no-repeat;
background-position: left center;
}
+}
+
+@media only screen and (max-width: 1000px) {
+ .antimodeMenu-cont {
+ position: absolute;
+ z-index: 10000;
+ height: 100px;
+ background: #323232;
+ box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
+ border-radius: 0px 6px 6px 6px;
+ // overflow: hidden;
+ display: flex;
+
+ &.with-rows {
+ flex-direction: column-reverse;
+ }
+
+ .antimodeMenu-row {
+ display: flex;
+ height: 100%;
+ width:100%;
+ }
+
+ .antimodeMenu-button {
+ background-color: transparent;
+ width: 100px;
+ height: 100px;
+
+ &.active {
+ background-color: #121212;
+ }
+ }
+
+ .antimodeMenu-button:hover {
+ background-color: #121212;
+ }
+
+ .antimodeMenu-dragger {
+ height: 100%;
+ transition: width .2s;
+ background-image: url("https://logodix.com/logo/1020374.png");
+ background-size: 90% 100%;
+ background-repeat: no-repeat;
+ background-position: left center;
+ }
+ }
} \ No newline at end of file
diff --git a/src/client/views/GestureOverlay.scss b/src/client/views/GestureOverlay.scss
index 107077792..f61f4a05e 100644
--- a/src/client/views/GestureOverlay.scss
+++ b/src/client/views/GestureOverlay.scss
@@ -1,7 +1,7 @@
.gestureOverlay-cont {
width: 100vw;
height: 100vh;
- position: absolute;
+ position: fixed;
top: 0;
left: 0;
touch-action: none;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index f00fd7cb4..97df86168 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -5,7 +5,6 @@ import { Doc } from "../../fields/Doc";
import { InkData, InkTool } from "../../fields/InkField";
import { Cast, FieldValue, NumCast } from "../../fields/Types";
import MobileInkOverlay from "../../mobile/MobileInkOverlay";
-import MobileInterface from "../../mobile/MobileInterface";
import { GestureUtils } from "../../pen-gestures/GestureUtils";
import { MobileInkOverlayContent } from "../../server/Message";
import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from "../../Utils";
@@ -24,6 +23,7 @@ import { RadialMenu } from "./nodes/RadialMenu";
import HorizontalPalette from "./Palette";
import { Touchable } from "./Touchable";
import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu";
+import { MobileInterface } from "../../mobile/MobileInterface";
@observer
export default class GestureOverlay extends Touchable {
@@ -107,7 +107,7 @@ export default class GestureOverlay extends Touchable {
onReactTouchStart = (te: React.TouchEvent) => {
document.removeEventListener("touchmove", this.onReactHoldTouchMove);
document.removeEventListener("touchend", this.onReactHoldTouchEnd);
- if (RadialMenu.Instance._display === true) {
+ if (RadialMenu.Instance?._display === true) {
te.preventDefault();
te.stopPropagation();
RadialMenu.Instance.closeMenu();
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index f65a89422..bd0e4fc9a 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -87,7 +87,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
if (!e.isPropagationStopped()) {
- ContextMenu.Instance.addItem({
+ ContextMenu.Instance?.addItem({
description: "Make Hero Image", event: () => {
const index = NumCast(this.layoutDoc._itemIndex);
(this.dataDoc || Doc.GetProto(this.props.Document)).hero = ObjectField.MakeCopy(this.childLayoutPairs[index].layout.data as ObjectField);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 6f5a3dfe4..02ba45f9c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -840,7 +840,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
focus={emptyFunction}
- backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+ backgroundColor={CollectionDockingView.Instance?.props.backgroundColor}
addDocTab={this.addDocTab}
pinToPres={DockedFrameRenderer.PinDoc}
ContainingCollectionView={undefined}
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 203c51163..98efdfd23 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -33,8 +33,9 @@
.collectionStackingViewFieldColumn {
height: max-content;
}
+
.collectionStackingViewFieldColumnDragging {
- height:100%;
+ height: 100%;
}
.collectionSchemaView-previewDoc {
@@ -421,4 +422,15 @@
.rc-switch-checked .rc-switch-inner {
left: 8px;
}
+}
+
+@media only screen and (max-width: 1000px) {
+
+ .collectionStackingView .collectionStackingView-columnDragger,
+ .collectionMasonryView .collectionStackingView-columnDragger {
+ width: 0.1;
+ height: 0.1;
+ opacity: 0;
+ font-size: 0;
+ }
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 215b5bce8..9f5308ce8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -216,12 +216,12 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) {
- const existingVm = ContextMenu.Instance.findByDescription(category);
+ const existingVm = ContextMenu.Instance?.findByDescription(category);
const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : [];
subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" });
if (addExtras && CollectionView._safeMode) {
- ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" });
+ ContextMenu.Instance?.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" });
}
subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" });
subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
@@ -239,7 +239,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
}
addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
- !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" });
+ !existingVm && ContextMenu.Instance?.addItem({ description: category, subitems: subItems, icon: "eye" });
}
onContextMenu = (e: React.MouseEvent): void => {
@@ -251,7 +251,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return newRendition;
}, false);
- const existing = ContextMenu.Instance.findByDescription("Options...");
+ const existing = ContextMenu.Instance?.findByDescription("Options...");
const layoutItems = existing && "subitems" in existing ? existing.subitems : [];
layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
if (this.props.Document.childLayout instanceof Doc) {
@@ -262,9 +262,9 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
}
layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
- !existing && ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" });
+ !existing && ContextMenu.Instance?.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" });
- const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
+ const existingOnClick = ContextMenu.Instance?.findByDescription("OnClick...");
const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
const funcs = [
{ key: "onChildClick", name: "On Child Clicked" },
@@ -280,12 +280,12 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
icon: "edit",
event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)),
}));
- !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
+ !existingOnClick && ContextMenu.Instance?.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
- const more = ContextMenu.Instance.findByDescription("More...");
+ const more = ContextMenu.Instance?.findByDescription("More...");
const moreItems = more && "subitems" in more ? more.subitems : [];
moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) });
- !more && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
+ !more && ContextMenu.Instance?.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 11a14a862..cddac01ad 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -596,7 +596,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
// bcz: theres should be a better way of doing these than referencing these static instances directly
MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2
- PDFMenu.Instance.fadeOut(true);
+ // PDFMenu.Instance.fadeOut(true);
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
index a7f4d4e53..72fdf5af9 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
@@ -4,7 +4,6 @@
height: 100%;
}
-
}
.sketch-picker {
@@ -31,6 +30,42 @@
background: #323232;
display: block;
+ }
+}
+@media only screen and (max-width: 1000px) {
+ .antimodeMenu-button {
+ .color-preview {
+ width: 100%;
+ height: 100%;
+ }
+
+ }
+
+ .sketch-picker {
+ background: #323232;
+
+ .flexbox-fit {
+ background: #323232;
+ }
}
-} \ No newline at end of file
+
+ .btn-group {
+ display: grid;
+ grid-template-columns: auto auto;
+ /* Make the buttons appear below each other */
+ }
+
+ .btn2-group {
+ display: block;
+ background: #323232;
+ grid-template-columns: auto;
+
+ /* Make the buttons appear below each other */
+ .antimodeMenu-button {
+ background: #323232;
+ display: block;
+
+ }
+ }
+}
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 5a27f74e5..8bebcd047 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -11,6 +11,8 @@ import { Utils } from "../../../../Utils";
import GestureOverlay from "../../GestureOverlay";
import { Doc } from "../../../../fields/Doc";
+
+
@observer
export default class InkOptionsMenu extends AntimodeMenu {
static Instance: InkOptionsMenu;
@@ -23,6 +25,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
@observable _colorBtn = false;
@observable _widthBtn = false;
+
+
constructor(props: Readonly<{}>) {
super(props);
InkOptionsMenu.Instance = this;
@@ -101,7 +105,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
title={`Draw ${btn}`}
key={btn}
onPointerDown={action(e => GestureOverlay.Instance.InkShape = btn)}
- style={{ backgroundColor: btn === GestureOverlay.Instance.InkShape ? "121212" : "" }}>
+ style={{ backgroundColor: btn === GestureOverlay.Instance?.InkShape ? "121212" : "" }}>
{this._icons[i]}
</button>)},
</>;
@@ -113,7 +117,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
title="Bezier changer"
key="bezier"
onPointerDown={e => this.changeBezier(e)}
- style={ { backgroundColor:ActiveInkBezierApprox() ? "121212":"" } }>
+ style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
B
</button>;
}
@@ -126,7 +130,15 @@ export default class InkOptionsMenu extends AntimodeMenu {
this.widthPicker,
this.colorPicker,
];
- return this.getElement(buttons);
+
+ const mobileButtons = [
+ this.shapeButtons,
+ this.bezierButton,
+ this.widthPicker,
+ this.colorPicker,
+ ];
+
+ return (window.innerWidth < 1000 ? this.getElement(mobileButtons) : this.getElement(buttons));
}
}
Scripting.addGlobal(function activatePen(penBtn: any) {
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index 53b54d7e4..61ce4bd13 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -1,141 +1,169 @@
-.audiobox-container, .audiobox-container-interactive {
+.audiobox-container,
+.audiobox-container-interactive {
width: 100%;
height: 100%;
position: inherit;
- display:flex;
+ display: flex;
pointer-events: all;
- cursor:default;
+ cursor: default;
+
.audiobox-buttons {
display: flex;
width: 100%;
align-items: center;
}
+
.audiobox-handle {
- width:20px;
- height:100%;
- display:inline-block;
+ width: 20px;
+ height: 100%;
+ display: inline-block;
}
- .audiobox-control, .audiobox-control-interactive {
- top:0;
+
+ .audiobox-control,
+ .audiobox-control-interactive {
+ top: 0;
max-height: 32px;
width: 100%;
- display:inline-block;
+ display: inline-block;
pointer-events: none;
}
+
.audiobox-control-interactive {
pointer-events: all;
}
+
.audiobox-record {
pointer-events: all;
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
position: relative;
pointer-events: none;
}
+
.audiobox-record-interactive {
pointer-events: all;
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
position: relative;
}
+
.audiobox-controls {
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
position: relative;
display: flex;
padding-left: 2px;
+
.audiobox-player {
- margin-top:auto;
- margin-bottom:auto;
- width:100%;
+ margin-top: auto;
+ margin-bottom: auto;
+ width: 100%;
height: 80%;
position: relative;
padding-right: 5px;
display: flex;
- .audiobox-playhead, .audiobox-dictation {
+
+ .audiobox-playhead,
+ .audiobox-dictation {
position: relative;
margin-top: auto;
margin-bottom: auto;
width: 25px;
padding: 2px;
}
+
.audiobox-dictation {
align-items: center;
display: inherit;
background: dimgray;
}
+
.audiobox-timeline {
- position:relative;
- height:100%;
- width:100%;
+ position: relative;
+ height: 100%;
+ width: 100%;
background: white;
border: gray solid 1px;
border-radius: 3px;
+
.audiobox-current {
width: 1px;
- height:100%;
+ height: 100%;
background-color: red;
position: absolute;
}
- .audiobox-linker, .audiobox-linker-mini {
- position:absolute;
- width:15px;
- min-height:10px;
- height:15px;
- margin-left:-2.55px;
- background:gray;
+
+ .audiobox-linker,
+ .audiobox-linker-mini {
+ position: absolute;
+ width: 15px;
+ min-height: 10px;
+ height: 15px;
+ margin-left: -2.55px;
+ background: gray;
border-radius: 100%;
- opacity:0.9;
+ opacity: 0.9;
background-color: transparent;
box-shadow: black 2px 2px 1px;
+
.linkAnchorBox-cont {
position: relative !important;
- height: 100% !important;
+ height: 100% !important;
width: 100% !important;
- left:unset !important;
- top:unset !important;
+ left: unset !important;
+ top: unset !important;
}
}
+
.audiobox-linker-mini {
- width:8px;
- min-height:8px;
- height:8px;
+ width: 8px;
+ min-height: 8px;
+ height: 8px;
box-shadow: black 1px 1px 1px;
margin-left: -1;
margin-top: -2;
+
.linkAnchorBox-cont {
position: relative !important;
- height: 100% !important;
+ height: 100% !important;
width: 100% !important;
- left:unset !important;
- top:unset !important;
+ left: unset !important;
+ top: unset !important;
}
}
- .audiobox-linker:hover, .audiobox-linker-mini:hover {
- opacity:1;
+
+ .audiobox-linker:hover,
+ .audiobox-linker-mini:hover {
+ opacity: 1;
}
- .audiobox-marker-container, .audiobox-marker-minicontainer {
- position:absolute;
- width:10px;
- height:90%;
- top:2.5%;
- background:gray;
+
+ .audiobox-marker-container,
+ .audiobox-marker-minicontainer {
+ position: absolute;
+ width: 10px;
+ height: 90%;
+ top: 2.5%;
+ background: gray;
border-radius: 5px;
box-shadow: black 2px 2px 1px;
+
.audiobox-marker {
- position:relative;
+ position: relative;
height: calc(100% - 15px);
margin-top: 15px;
}
+
.audio-marker:hover {
border: orange 2px solid;
}
}
+
.audiobox-marker-minicontainer {
- width:5px;
+ width: 5px;
border-radius: 1px;
+
.audiobox-marker {
- position:relative;
+ position: relative;
height: calc(100% - 8px);
margin-top: 8px;
}
@@ -143,4 +171,80 @@
}
}
}
+}
+
+
+@media only screen and (max-width: 1000px) {
+
+ .audiobox-container,
+ .audiobox-container-interactive {
+ width: max-content;
+ /* align-self: center; */
+ left: 50%;
+ top: 40%;
+ transform: translate(-50%, 0);
+ height: 100px;
+ position: absolute;
+ display: flex;
+ pointer-events: all;
+ /* cursor: default; */
+ }
+
+ .audiobox-container .audiobox-buttons,
+ .audiobox-container-interactive .audiobox-buttons {
+ display: flex;
+ width: 500px;
+ /* left: 50%; */
+ /* transform: translate(-50%,0); */
+ align-items: center;
+ }
+
+ .audiobox-dictation {
+ width: 100;
+ height: 100;
+ font-size: 50;
+ /* background-color: white; */
+ }
+
+ .audiobox-container .audiobox-record-interactive,
+ .audiobox-container-interactive .audiobox-record-interactive {
+ width: 95%;
+ user-select: none;
+ font-size: 50px;
+ font-weight: 100;
+ left: 5%;
+ height: 100%;
+ position: relative;
+ }
+
+ .audiobox-container .audiobox-controls .audiobox-player .audiobox-playhead,
+ .audiobox-container .audiobox-controls .audiobox-player .audiobox-dictation,
+ .audiobox-container-interactive .audiobox-controls .audiobox-player .audiobox-playhead,
+ .audiobox-container-interactive .audiobox-controls .audiobox-player .audiobox-dictation {
+ position: relative;
+ align-self: center;
+ width: 50px;
+ height: max-content;
+ padding: 0;
+ }
+
+ .audiobox-container .audiobox-controls .audiobox-player,
+ .audiobox-container-interactive .audiobox-controls .audiobox-player {
+ margin-top: auto;
+ margin-bottom: auto;
+ width: 100%;
+ height: 100%;
+ position: relative;
+ padding-right: 5px;
+ display: flex;
+ }
+
+ .audiobox-container .audiobox-controls,
+ .audiobox-container-interactive .audiobox-controls {
+ width: 500px;
+ height: 100%;
+ position: relative;
+ display: flex;
+ padding-left: 2px;
+ }
} \ No newline at end of file
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 0d6258cf3..f49b1f763 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -60,9 +60,9 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
StrCast(selDoc?._backgroundColor, StrCast(selDoc?.backgroundColor, "black")))} />
<div style={{ display: "grid", gridTemplateColumns: "20% 80%", paddingTop: "10px" }}>
<div> {ActiveInkWidth() ?? 2}</div>
- <input type="range" value={ActiveInkWidth() ?? 2} defaultValue={2} min={1} max={100} onChange={(e: React.ChangeEvent<HTMLInputElement>) => SetActiveInkWidth(e.target.value)} />
+ <input type="range" value={ActiveInkWidth() ?? 2} min={1} max={100} onChange={(e: React.ChangeEvent<HTMLInputElement>) => SetActiveInkWidth(e.target.value)} />
<div> {ActiveInkBezierApprox() ?? 2}</div>
- <input type="range" value={ActiveInkBezierApprox() ?? 2} defaultValue={2} min={0} max={300} onChange={(e: React.ChangeEvent<HTMLInputElement>) => SetActiveBezierApprox(e.target.value)} />
+ <input type="range" value={ActiveInkBezierApprox() ?? 2} min={0} max={300} onChange={(e: React.ChangeEvent<HTMLInputElement>) => SetActiveBezierApprox(e.target.value)} />
<br />
<br />
</div>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d1877c3a0..ccae9658f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -139,7 +139,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
document.removeEventListener("pointerup", this.onPointerUp);
console.log(SelectionManager.SelectedDocuments());
console.log("START");
- if (RadialMenu.Instance._display === false) {
+ if (RadialMenu.Instance?._display === false) {
this.addHoldMoveListeners();
this.addHoldEndListeners();
this.onRadialMenu(e, me);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index cabf30c13..73410e02f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -174,19 +174,19 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
// }), icon: "expand-arrows-alt"
// });
- const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+ const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers...");
const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
//modes.push({ description: "Recommend", event: this.extractText, icon: "brain" });
- !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
+ !existingAnalyze && ContextMenu.Instance?.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
- ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
- const existingMore = ContextMenu.Instance.findByDescription("More...");
+ const existingMore = ContextMenu.Instance?.findByDescription("More...");
const mores: ContextMenuProps[] = existingMore && "subitems" in existingMore ? existingMore.subitems : [];
- !existingMore && ContextMenu.Instance.addItem({ description: "More...", subitems: mores, icon: "hand-point-right" });
+ !existingMore && ContextMenu.Instance?.addItem({ description: "More...", subitems: mores, icon: "hand-point-right" });
}
}
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index d48000e16..2bb249ee4 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -16,6 +16,7 @@
height: calc(100% - 25px);
width: 100%;
}
+
.presBox-buttons {
width: 100%;
background: gray;
@@ -24,6 +25,7 @@
display: grid;
grid-column-end: 4;
grid-column-start: 1;
+
.presBox-viewPicker {
height: 25;
position: relative;
@@ -31,10 +33,12 @@
grid-column: 1/2;
min-width: 15px;
}
+
select {
background: #323232;
color: white;
}
+
.presBox-button {
margin-right: 2.5%;
margin-left: 2.5%;
@@ -44,10 +48,12 @@
align-items: center;
background: #323232;
color: white;
+
svg {
margin: auto;
}
}
+
.collectionViewBaseChrome-viewPicker {
min-width: 50;
width: 5%;
@@ -56,17 +62,68 @@
display: inline-block;
}
}
- .presBox-backward, .presBox-forward {
+
+ .presBox-backward,
+ .presBox-forward {
width: 25px;
border-radius: 5px;
- top:50%;
+ top: 50%;
position: absolute;
display: inline-block;
}
+
.presBox-backward {
- left:5;
+ left: 5;
}
+
.presBox-forward {
- right:5;
+ right: 5;
+ }
+}
+
+@media only screen and (max-width: 1000px) {
+ .presBox-cont .presBox-buttons {
+ position: absolute;
+ top: 70%;
+ left: 50%;
+ transform: translate(-50%, 0);
+ width: max-content;
+ height: 15%;
+ z-index: 2;
+ align-items: center;
+ background: rgba(0, 0, 0, 0);
+ padding-top: 5px;
+ padding-bottom: 5px;
+ display: inline-flex;
+ }
+
+ .presBox-cont .presBox-listCont {
+ position: absolute;
+ top: 50;
+ height: calc(100% - 80px);
+ width: 100%;
+ }
+
+ .presBox-cont .presBox-buttons .presBox-button {
+ margin-right: 10px;
+ margin-left: 10px;
+ height: 250;
+ width: 250;
+ font-size: 70;
+ border-radius: 25px;
+ display: flex;
+ align-items: center;
+ background: #323232;
+ color: white;
+ }
+
+ .presBox-cont .presBox-buttons .presBox-viewPicker {
+ top: -70;
+ left: 2.5%;
+ height: 50;
+ width: 95%;
+ font-size: 30px;
+ position: absolute;
+ min-width: 50px;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index df4a05dd7..7b0ceb6cf 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -37,6 +37,7 @@
position: absolute;
}
}
+
.formattedTextBox-outer {
position: relative;
overflow: auto;
@@ -316,4 +317,284 @@ footnote::after {
.multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
.multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
.multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
-} \ No newline at end of file
+}
+
+@media only screen and (max-width: 1000px) {
+ @import "../../globalCssVariables";
+
+ .ProseMirror {
+ width: 100%;
+ height: 100%;
+ min-height: 100%;
+ }
+
+ .ProseMirror:focus {
+ outline: none !important;
+ }
+
+ .formattedTextBox-cont {
+ touch-action: none;
+ cursor: text;
+ background: inherit;
+ padding: 0;
+ border-width: 0px;
+ border-radius: inherit;
+ border-color: $intermediate-color;
+ box-sizing: border-box;
+ background-color: inherit;
+ border-style: solid;
+ overflow-y: auto;
+ overflow-x: hidden;
+ color: initial;
+ max-height: 100%;
+ display: flex;
+ flex-direction: row;
+ transition: opacity 1s;
+
+ .formattedTextBox-dictation {
+ height: 12px;
+ width: 10px;
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ }
+ }
+
+ .formattedTextBox-outer {
+ position: relative;
+ overflow: auto;
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+ }
+
+ .formattedTextBox-sidebar-handle {
+ position: absolute;
+ top: calc(50% - 17.5px);
+ width: 10px;
+ height: 35px;
+ background: lightgray;
+ border-radius: 20px;
+ cursor:grabbing;
+ }
+
+ .formattedTextBox-cont>.formattedTextBox-sidebar-handle {
+ right: 0;
+ left: unset;
+ }
+
+ .formattedTextBox-sidebar,
+ .formattedTextBox-sidebar-inking {
+ border-left: dashed 1px black;
+ height: 100%;
+ display: inline-block;
+ position: absolute;
+ right: 0;
+
+ .collectionfreeformview-container {
+ position: relative;
+ }
+
+ >.formattedTextBox-sidebar-handle {
+ right: unset;
+ left: -5;
+ }
+ }
+
+ .formattedTextBox-sidebar-inking {
+ pointer-events: all;
+ }
+
+ .formattedTextBox-inner-rounded {
+ height: 70%;
+ width: 85%;
+ position: absolute;
+ overflow: auto;
+ top: 15%;
+ left: 10%;
+ }
+
+ .formattedTextBox-inner-rounded,
+ .formattedTextBox-inner {
+ height: 100%;
+ white-space: pre-wrap;
+ hr {
+ display: block;
+ unicode-bidi: isolate;
+ margin-block-start: 0.5em;
+ margin-block-end: 0.5em;
+ margin-inline-start: auto;
+ margin-inline-end: auto;
+ overflow: hidden;
+ border-style: inset;
+ border-width: 1px;
+ }
+ }
+
+ // .menuicon {
+ // display: inline-block;
+ // border-right: 1px solid rgba(0, 0, 0, 0.2);
+ // color: #888;
+ // line-height: 1;
+ // padding: 0 7px;
+ // margin: 1px;
+ // cursor: pointer;
+ // text-align: center;
+ // min-width: 1.4em;
+ // }
+
+ .strong,
+ .heading {
+ font-weight: bold;
+ }
+
+ .em {
+ font-style: italic;
+ }
+
+ .userMarkOpen {
+ background: rgba(255, 255, 0, 0.267);
+ display: inline;
+ }
+
+ .userMark {
+ background: rgba(255, 255, 0, 0.267);
+ font-size: 2px;
+ display: inline-grid;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 10px;
+ min-height: 10px;
+ text-align: center;
+ align-content: center;
+ }
+
+ footnote {
+ display: inline-block;
+ position: relative;
+ cursor: pointer;
+
+ div {
+ padding: 0 !important;
+ }
+ }
+
+ footnote::after {
+ content: counter(prosemirror-footnote);
+ vertical-align: super;
+ font-size: 75%;
+ counter-increment: prosemirror-footnote;
+ }
+
+ .ProseMirror {
+ counter-reset: prosemirror-footnote;
+ }
+
+ .footnote-tooltip {
+ cursor: auto;
+ font-size: 75%;
+ position: absolute;
+ left: -30px;
+ top: calc(100% + 10px);
+ background: silver;
+ padding: 3px;
+ border-radius: 2px;
+ max-width: 100px;
+ min-width: 50px;
+ width: max-content;
+ }
+
+ .prosemirror-attribution {
+ font-size: 8px;
+ }
+
+ .footnote-tooltip::before {
+ border: 5px solid silver;
+ border-top-width: 0px;
+ border-left-color: transparent;
+ border-right-color: transparent;
+ position: absolute;
+ top: -5px;
+ left: 27px;
+ content: " ";
+ height: 0;
+ width: 0;
+ }
+
+
+ .formattedTextBox-inlineComment {
+ position: relative;
+ width: 40px;
+ height: 20px;
+ &::before {
+ content: "→";
+ }
+ &:hover {
+ background: orange;
+ }
+ }
+
+ .formattedTextBox-summarizer {
+ opacity: 0.5;
+ position: relative;
+ width: 40px;
+ height: 20px;
+ &::after {
+ content: "←";
+ }
+ }
+
+ .formattedTextBox-summarizer-collapsed {
+ opacity: 0.5;
+ position: relative;
+ width: 40px;
+ height: 20px;
+ &::after {
+ content: "...";
+ }
+ }
+
+ .ProseMirror {
+ touch-action: none;
+ span {
+ font-family: inherit;
+ }
+
+ ol, ul {
+ counter-reset: deci1 0 multi1 0;
+ padding-left: 1em;
+ font-family: inherit;
+ }
+ ol {
+ margin-left: 1em;
+ font-family: inherit;
+ }
+
+ .decimal1-ol { counter-reset: deci1; p {display: inline; font-family: inherit} margin-left: 0; }
+ .decimal2-ol { counter-reset: deci2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1em;}
+ .decimal3-ol { counter-reset: deci3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
+ .decimal4-ol { counter-reset: deci4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3em;}
+ .decimal5-ol { counter-reset: deci5; p {display: inline; font-family: inherit} font-size: smaller; }
+ .decimal6-ol { counter-reset: deci6; p {display: inline; font-family: inherit} font-size: smaller; }
+ .decimal7-ol { counter-reset: deci7; p {display: inline; font-family: inherit} font-size: smaller; }
+
+ .multi1-ol { counter-reset: multi1; p {display: inline; font-family: inherit} margin-left: 0; padding-left: 1.2em }
+ .multi2-ol { counter-reset: multi2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1.4em;}
+ .multi3-ol { counter-reset: multi3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
+ .multi4-ol { counter-reset: multi4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
+
+ .decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
+ .decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
+ .decimal3:before { transition: 0.5s;counter-increment: deci3; display: inline-block; margin-left: -2.85em;width: 2.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) ". "; }
+ .decimal4:before { transition: 0.5s;counter-increment: deci4; display: inline-block; margin-left: -3.85em;width: 3.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) ". "; }
+ .decimal5:before { transition: 0.5s;counter-increment: deci5; display: inline-block; margin-left: -2em; width: 5em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ". "; }
+ .decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; }
+ .decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; }
+
+ .multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
+ .multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
+ .multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
+ .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
+ }
+}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fc5ab50d9..1db50a5cc 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -188,7 +188,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
const state = this._editorView.state.apply(tx);
- this._editorView.updateState(state);
+ this?._editorView?.updateState(state);
(tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks);
const tsel = this._editorView.state.selection.$from;
@@ -1225,7 +1225,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
if (this.props.isSelected()) {
- this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props);
+ this._editorView && RichTextMenu.Instance?.updateFromDash(this._editorView, undefined, this.props);
} else if (FormattedTextBoxComment.textBox === this) {
FormattedTextBoxComment.Hide();
}
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index ccd2e8947..ec82b0c51 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -13,9 +13,10 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
- transition: all .1s;
+ transition: all .1s;
padding: 0px;
padding-bottom: 3px;
+
.documentView-node {
position: absolute;
z-index: 1;
@@ -45,7 +46,7 @@
.presElementBox-closeIcon {
border-radius: 20px;
- transform:scale(0.7);
+ transform: scale(0.7);
position: absolute;
right: 0;
top: 0;
@@ -58,6 +59,7 @@
position: relative;
width: 100%;
height: auto;
+
.presElementBox-interaction {
color: gray;
float: left;
@@ -65,6 +67,7 @@
width: 20px;
height: 20px;
}
+
.presElementBox-interaction-selected {
color: white;
float: left;
@@ -90,15 +93,93 @@
display: flex;
width: auto;
justify-content: center;
- margin:auto;
+ margin: auto;
}
.presElementBox-embeddedMask {
- width:100%;
- height:100%;
+ width: 100%;
+ height: 100%;
position: absolute;
- left:0;
- top:0;
+ left: 0;
+ top: 0;
background: transparent;
- z-index:2;
+ z-index: 2;
+}
+
+@media only screen and (max-width: 1000px) {
+ .presElementBox-buttons {
+ display: inline-flex;
+ position: relative;
+ width: 100%;
+ }
+
+ .presElementBox-item {
+ display: inline-flex;
+ }
+
+ .presElementBox-buttons .presElementBox-interaction {
+ color: gray;
+ float: left;
+ padding: 0px;
+ width: 50;
+ height: 50;
+ }
+
+ .presElementBox-buttons .presElementBox-interaction-selected {
+ color: white;
+ float: left;
+ padding: 0px;
+ width: 50;
+ height: 50;
+ border: solid 1px darkgray;
+ }
+
+ .presElementBox-closeIcon {
+ border-radius: 20px;
+ transform: scale(1.5);
+ position: absolute;
+ right: 10;
+ top: 10;
+ padding: 8px;
+ }
+
+ .presElementBox-buttons {
+ display: inline-flex;
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 50%;
+ }
+
+ .presElementBox-name {
+ font-size: 30px;
+ position: absolute;
+ display: inline-block;
+ top: 10px;
+ width: 50%;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: pre;
+ }
+
+ .presElementBox-item {
+ display: inline-block;
+ background-color: #eeeeee;
+ pointer-events: all;
+ width: 100%;
+ min-height: 100%;
+ height: max-content;
+ outline-color: maroon;
+ outline-style: dashed;
+ border-radius: 6px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ transition: all .1s;
+ padding: 0px;
+ padding-bottom: 3px;
+ }
} \ No newline at end of file
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index caee06d8f..793d4068f 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -49,7 +49,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
componentDidMount() {
this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
- params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+ params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 200 : 0), { fireImmediately: true });
}
componentWillUnmount() {
this._heightDisposer?.();
diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss
index eea69b81c..95c0c2680 100644
--- a/src/mobile/ImageUpload.scss
+++ b/src/mobile/ImageUpload.scss
@@ -5,8 +5,30 @@
justify-content: center;
flex-direction: column;
align-items: center;
- width: 100vw;
- height: 100vh;
+ max-width: 400px;
+ min-width: 400px;
+
+ .upload_label {
+ font-size: 3em;
+ font-weight: 700;
+ color: white;
+ background-color: black;
+ display: inline-block;
+ margin: 10;
+ width: 100%;
+ border-radius: 10px;
+ }
+
+ .file {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ direction: ltr;
+ }
+
+ .upload_label:hover {
+ background-color: darkred;
+ }
.button_file {
text-align: center;
@@ -17,18 +39,96 @@
font-size: 3em;
}
- .input_file {
- display: none;
+ .inputfile {
+ width: 0.1px;
+ height: 0.1px;
+ opacity: 0;
+ overflow: hidden;
+ position: absolute;
+ z-index: -1;
}
- .upload_label,
- .upload_button {
- background: $dark-color;
- font-size: 500%;
- font-family: $sans-serif;
- text-align: center;
- padding: 5vh;
- margin-bottom: 20px;
+ .inputfile+label {
+ font-size: 3em;
+ font-weight: 700;
color: white;
+ background-color: black;
+ display: inline-block;
+ margin: 10px;
+ width: 100%;
+ border-radius: 10px;
+ }
+
+ .inputfile:focus+label,
+ .inputfile+label:hover {
+ background-color: darkred;
}
+
+ .status {
+ font-size: 2em;
+ }
+
+}
+
+.backgroundUpload {
+ height: 100vh;
+ top: 0;
+ z-index: 999;
+ width: 100vw;
+ position: absolute;
+ background-color: lightgrey;
+ opacity: 0.4;
+}
+
+.image-upload {
+ top: 100%;
+ opacity: 0;
+}
+
+.image-upload.active {
+ top: 0;
+ position: absolute;
+ z-index: 999;
+ height: 100vh;
+ width: 100vw;
+ opacity: 1;
+}
+
+.uploadContainer {
+ top: 40;
+ position: absolute;
+ z-index: 1000;
+ height: 20vh;
+ width: 80vw;
+ opacity: 1;
+}
+
+.closeUpload {
+ position: absolute;
+ border-radius: 10px;
+ top: 39.7%;
+ color: grey;
+ font-size: 40;
+ left: 65.8%;
+ z-index: 1002;
+ padding: 0px 3px;
+ background: aliceblue;
+ transition: 0.5s ease all;
+ border: 3px solid;
+ border-color: black;
+}
+
+.loadingImage {
+ display: inline-flex;
+ width: max-content;
+}
+
+.loadingSlab {
+ position: relative;
+ width: 30px;
+ height: 30px;
+ margin: 10;
+ border-radius: 20px;
+ opacity: 0.3;
+ background-color: black;
} \ No newline at end of file
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index b15042f9f..fc26ba882 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -4,16 +4,21 @@ import { Docs } from '../client/documents/Documents';
import "./ImageUpload.scss";
import React = require('react');
import { DocServer } from '../client/DocServer';
-import { Opt, Doc } from '../fields/Doc';
+import { observer } from 'mobx-react';
+import { observable, action } from 'mobx';
+import { Utils } from '../Utils';
+import { Networking } from '../client/Network';
+import { Doc, Opt } from '../fields/Doc';
import { Cast } from '../fields/Types';
import { listSpec } from '../fields/Schema';
import { List } from '../fields/List';
-import { observer } from 'mobx-react';
-import { observable } from 'mobx';
-import { Utils } from '../Utils';
-import MobileInterface from './MobileInterface';
-import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
-import { resolvedPorts } from '../client/views/Main';
+import { Scripting } from '../client/util/Scripting';
+import MainViewModal from '../client/views/MainViewModal';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+export interface ImageUploadProps {
+ Document: Doc;
+}
// const onPointerDown = (e: React.TouchEvent) => {
// let imgInput = document.getElementById("input_image_file");
@@ -24,105 +29,192 @@ import { resolvedPorts } from '../client/views/Main';
const inputRef = React.createRef<HTMLInputElement>();
@observer
-class Uploader extends React.Component {
+export class Uploader extends React.Component {
@observable error: string = "";
@observable status: string = "";
+ @observable nm: string = "Choose files";
+ @observable process: string = "";
onClick = async () => {
- console.log("uploader click");
try {
- this.status = "initializing protos";
await Docs.Prototypes.initialize();
const imgPrev = document.getElementById("img_preview");
+ const slab1 = document.getElementById("slab1");
+ if (slab1) {
+ slab1.style.opacity = "1";
+ }
if (imgPrev) {
const files: FileList | null = inputRef.current!.files;
+ const slab2 = document.getElementById("slab2");
+ if (slab2) {
+ slab2.style.opacity = "1";
+ }
if (files && files.length !== 0) {
- console.log(files[0]);
- const name = files[0].name;
- const formData = new FormData();
- formData.append("file", files[0]);
-
- const upload = window.location.origin + "/uploadFormData";
- this.status = "uploading image";
- console.log("uploading image", formData);
- const res = await fetch(upload, {
- method: 'POST',
- body: formData
- });
- this.status = "upload image, getting json";
- const json = await res.json();
- json.map(async (file: any) => {
- const path = window.location.origin + file;
- const doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name });
-
- this.status = "getting user document";
-
- const res = await rp.get(Utils.prepend("/getUserDocumentId"));
- if (!res) {
- throw new Error("No user id returned");
- }
- const field = await DocServer.GetRefField(res);
- let pending: Opt<Doc>;
- if (field instanceof Doc) {
- pending = await Cast(field.rightSidebarCollection, Doc);
+ this.process = "Uploading Files";
+ for (let index = 0; index < files.length; ++index) {
+ const file = files[index];
+ const res = await Networking.UploadFilesToServer(file);
+ const slab3 = document.getElementById("slab3");
+ if (slab3) {
+ slab3.style.opacity = "1";
}
- if (pending) {
- this.status = "has pending docs";
- const data = await Cast(pending.data, listSpec(Doc));
- if (data) {
- data.push(doc);
+ res.map(async ({ result }) => {
+ const name = file.name;
+ if (result instanceof Error) {
+ return;
+ }
+ const path = Utils.prepend(result.accessPaths.agnostic.client);
+ let doc = null;
+ if (file.type === "video/mp4") {
+ doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name });
} else {
- pending.data = new List([doc]);
+ doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name });
}
- this.status = "finished";
- }
- });
-
- // console.log(window.location.origin + file[0])
+ const slab4 = document.getElementById("slab4");
+ if (slab4) {
+ slab4.style.opacity = "1";
+ }
+ const res = await rp.get(Utils.prepend("/getUserDocumentId"));
+ if (!res) {
+ throw new Error("No user id returned");
+ }
+ const field = await DocServer.GetRefField(res);
+ let pending: Opt<Doc>;
+ if (field instanceof Doc) {
+ pending = await Cast(field.rightSidebarCollection, Doc);
+ }
+ if (pending) {
+ const data = await Cast(pending.data, listSpec(Doc));
+ if (data) {
+ data.push(doc);
+ } else {
+ pending.data = new List([doc]);
+ }
+ this.status = "finished";
+ const slab5 = document.getElementById("slab5");
+ if (slab5) {
+ slab5.style.opacity = "1";
+ }
+ this.process = "File " + (index + 1).toString() + " Uploaded";
+ const slab6 = document.getElementById("slab6");
+ if (slab6) {
+ slab6.style.opacity = "1";
+ }
+ const slab7 = document.getElementById("slab7");
+ if (slab7) {
+ slab7.style.opacity = "1";
+ }
- //imgPrev.setAttribute("src", window.location.origin + files[0].name)
+ }
+ });
+ }
+ } else {
+ this.process = "No file selected";
}
+ setTimeout(this.clearUpload, 3000);
}
} catch (error) {
this.error = JSON.stringify(error);
}
}
- render() {
+ // Updates label after a files is selected (so user knows a file is uploaded)
+ inputLabel = async () => {
+ const files: FileList | null = inputRef.current!.files;
+ await files;
+ if (files && files.length === 1) {
+ console.log(files);
+ this.nm = files[0].name;
+ } else if (files && files.length > 1) {
+ console.log(files.length);
+ this.nm = files.length.toString() + " files selected";
+ }
+ }
+
+ @action
+ clearUpload = () => {
+ const slab1 = document.getElementById("slab1");
+ if (slab1) {
+ slab1.style.opacity = "0.4";
+ }
+ const slab2 = document.getElementById("slab2");
+ if (slab2) {
+ slab2.style.opacity = "0.4";
+ }
+ const slab3 = document.getElementById("slab3");
+ if (slab3) {
+ slab3.style.opacity = "0.4";
+ }
+ const slab4 = document.getElementById("slab4");
+ if (slab4) {
+ slab4.style.opacity = "0.4";
+ }
+ const slab5 = document.getElementById("slab5");
+ if (slab5) {
+ slab5.style.opacity = "0.4";
+ }
+ const slab6 = document.getElementById("slab6");
+ if (slab6) {
+ slab6.style.opacity = "0.4";
+ }
+ const slab7 = document.getElementById("slab7");
+ if (slab7) {
+ slab7.style.opacity = "0.4";
+ }
+ this.nm = "Choose files";
+
+ if (inputRef.current) {
+ inputRef.current.value = "";
+ }
+ this.process = "";
+ console.log(inputRef.current!.files);
+ }
+
+
+
+ private get uploadInterface() {
return (
<div className="imgupload_cont">
- <label htmlFor="input_image_file" className="upload_label">Choose an Image</label>
- <input type="file" accept="image/*" className="input_file" id="input_image_file" ref={inputRef}></input>
- <button onClick={this.onClick} className="upload_button">Upload</button>
+ <input type="file" accept="video/*,image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel} multiple></input>
+ <label className="file" id="label" htmlFor="input_image_file">{this.nm}</label>
+ <div className="upload_label" onClick={this.onClick}>
+ <FontAwesomeIcon icon="upload" size="sm" />
+ Upload
+ </div>
+ {/* <div onClick={this.onClick} className="upload_button">Upload</div> */}
<img id="img_preview" src=""></img>
- <p>{this.status}</p>
- <p>{this.error}</p>
+ {/* <p>{this.status}</p>
+ <p>{this.error}</p> */}
+ <div className="loadingImage">
+ <div className="loadingSlab" id="slab1" />
+ <div className="loadingSlab" id="slab2" />
+ <div className="loadingSlab" id="slab3" />
+ <div className="loadingSlab" id="slab4" />
+ <div className="loadingSlab" id="slab5" />
+ <div className="loadingSlab" id="slab6" />
+ <div className="loadingSlab" id="slab7" />
+ </div>
+ <p className="status">{this.process}</p>
</div>
);
}
-}
-
+ @observable private dialogueBoxOpacity = 1;
+ @observable private overlayOpacity = 0.4;
-// DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts.socket, "image upload");
-(async () => {
- const info = await CurrentUserUtils.loadCurrentUser();
- DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts.socket, info.email + "mobile");
- await Docs.Prototypes.initialize();
- if (info.id !== "__guest__") {
- // a guest will not have an id registered
- await CurrentUserUtils.loadUserDocument(info);
+ render() {
+ return (
+ <MainViewModal
+ contents={this.uploadInterface}
+ isDisplayed={true}
+ interactive={true}
+ dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
+ overlayDisplayedOpacity={this.overlayOpacity}
+ />
+ );
}
- document.getElementById('root')!.addEventListener('wheel', event => {
- if (event.ctrlKey) {
- event.preventDefault();
- }
- }, true);
- ReactDOM.render((
- // <Uploader />
- <MobileInterface />
- ),
- document.getElementById('root')
- );
+
}
-)(); \ No newline at end of file
+
+
+// DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload");
diff --git a/src/mobile/MobileHome.scss b/src/mobile/MobileHome.scss
new file mode 100644
index 000000000..e1566b622
--- /dev/null
+++ b/src/mobile/MobileHome.scss
@@ -0,0 +1,101 @@
+$navbar-height: 120px;
+$pathbar-height: 50px;
+
+* {
+ margin: 0px;
+ padding: 0px;
+ box-sizing: border-box;
+ font-family: "Open Sans";
+}
+
+.homeContainer {
+ position: relative;
+ top: 200px;
+ overflow: scroll;
+ width: 100%;
+ left: 0;
+ height: calc(100% - 120px);
+ overflow-y: scroll;
+}
+
+.homeButton {
+ width: 96%;
+ margin-left: 2.5%;
+ height: 250px;
+ border-radius: 30px;
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+
+.iconRight {
+ position: absolute;
+ width: 50%;
+ height: 80px;
+ transform: translate(0, 50%);
+ right: 0px;
+ text-align: center;
+ font-size: 80;
+}
+
+.iconLeft {
+ position: absolute;
+ width: 50%;
+ height: 80px;
+ transform: translate(0%, 50%);
+ left: 0px;
+ text-align: center;
+ font-size: 80;
+}
+
+.textLeft {
+ position: absolute;
+ width: 50%;
+ left: 0px;
+ font-size: 40px;
+ text-align: left;
+ margin-left: 110px;
+ margin-top: 40px;
+ font-family: sans-serif;
+ font-weight: bold;
+}
+
+.textRight {
+ position: absolute;
+ width: 50%;
+ right: 0px;
+ font-size: 40px;
+ text-align: right;
+ margin-right: 110px;
+ margin-top: 40px;
+ font-family: sans-serif;
+ font-weight: bold;
+}
+
+.menuView {
+ position: absolute;
+ top: 135px;
+ left: 50%;
+ transform: translate(-50%, 0%);
+ display: flex;
+}
+
+.iconView {
+ height: 60px;
+ width: 60px;
+ background-color: darkgray;
+ border-radius: 5px;
+ border-style: solid;
+ border-width: 2px;
+ border-color: black;
+}
+
+.listView {
+ height: 60px;
+ width: 60px;
+ margin-left: 20;
+ background-color: darkgray;
+ border-radius: 5px;
+ border-style: solid;
+ border-width: 2px;
+ border-color: black;
+} \ No newline at end of file
diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx
index 59c73ed27..d668d134e 100644
--- a/src/mobile/MobileInkOverlay.tsx
+++ b/src/mobile/MobileInkOverlay.tsx
@@ -4,11 +4,9 @@ import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition
import { observable, action } from "mobx";
import { GestureUtils } from "../pen-gestures/GestureUtils";
import "./MobileInkOverlay.scss";
-import { StrCast, Cast } from '../fields/Types';
import { DragManager } from "../client/util/DragManager";
import { DocServer } from '../client/DocServer';
-import { Doc, DocListCastAsync } from '../fields/Doc';
-import { listSpec } from '../fields/Schema';
+import { Doc } from '../fields/Doc';
@observer
diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss
index 4d86e208f..215ce02e5 100644
--- a/src/mobile/MobileInterface.scss
+++ b/src/mobile/MobileInterface.scss
@@ -16,4 +16,21 @@
height: 100%;
position: relative;
touch-action: none;
+ width: 100%;
+
+ -webkit-touch-callout:none;
+ -webkit-user-select:none;
+ -khtml-user-select:none;
+ -moz-user-select:none;
+ -ms-user-select:none;
+ user-select:none;
+ -webkit-tap-highlight-color:rgba(0,0,0,0);
+}
+
+.mobileInterface-background {
+ height: 100%;
+ width: 100%;
+ position: relative;
+ touch-action: none;
+ background-color: pink;
} \ No newline at end of file
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index da14ffc88..25dc9fd55 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -1,47 +1,66 @@
-import React = require('react');
+import * as React from "react";
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEraser, faHighlighter, faLongArrowAltLeft, faMousePointer, faPenNib } from '@fortawesome/free-solid-svg-icons';
+import {
+ faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
+ faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
+ faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
+ faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
+ faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote,
+ faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft
+} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
+import * as rp from 'request-promise';
+import { Doc, DocListCast } from '../fields/Doc';
+import { FieldValue, Cast } from '../fields/Types';
+import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
+import { emptyPath, emptyFunction, returnFalse, returnOne, returnTrue, returnZero, Utils } from '../Utils';
import { DocServer } from '../client/DocServer';
import { Docs } from '../client/documents/Documents';
-import { DocumentManager } from '../client/util/DocumentManager';
-import RichTextMenu from '../client/views/nodes/formattedText/RichTextMenu';
import { Scripting } from '../client/util/Scripting';
-import { Transform } from '../client/util/Transform';
-import { DocumentDecorations } from '../client/views/DocumentDecorations';
-import GestureOverlay from '../client/views/GestureOverlay';
import { DocumentView } from '../client/views/nodes/DocumentView';
-import { RadialMenu } from '../client/views/nodes/RadialMenu';
-import { PreviewCursor } from '../client/views/PreviewCursor';
-import { Doc, DocListCast, FieldResult } from '../fields/Doc';
-import { Id } from '../fields/FieldSymbols';
+import { Transform } from '../client/util/Transform';
+import "./MobileInterface.scss";
+import "./MobileMenu.scss";
+import "./MobileHome.scss";
+import "./ImageUpload.scss";
+import { DocumentManager } from '../client/util/DocumentManager';
+import SettingsManager from '../client/util/SettingsManager';
+import { Uploader } from "./ImageUpload";
+import { DockedFrameRenderer } from '../client/views/collections/CollectionDockingView';
import { InkTool } from '../fields/InkField';
import { listSpec } from '../fields/Schema';
-import { Cast, FieldValue } from '../fields/Types';
-import { WebField } from "../fields/URLField";
-import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils';
-import "./MobileInterface.scss";
-import { CollectionView } from '../client/views/collections/CollectionView';
-import { InkingStroke } from '../client/views/InkingStroke';
+import { nullAudio } from '../fields/URLField';
+import GestureOverlay from "../client/views/GestureOverlay";
+import { ScriptField } from "../fields/ScriptField";
+import InkOptionsMenu from "../client/views/collections/collectionFreeForm/InkOptionsMenu";
-library.add(faLongArrowAltLeft);
+library.add(faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
+ faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
+ faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
+ faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
+ faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote,
+ faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft);
@observer
-export default class MobileInterface extends React.Component {
+export class MobileInterface extends React.Component {
@observable static Instance: MobileInterface;
@computed private get userDoc() { return Doc.UserDoc(); }
@computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; }
- // @observable private currentView: "main" | "ink" | "upload" = "main";
- private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc);
+ @observable private mainDoc: any = CurrentUserUtils.setupActiveMobile(this.userDoc);
@observable private renderView?: () => JSX.Element;
+ @observable private sidebarActive: boolean = false;
+ @observable private imageUploadActive: boolean = false;
+ @observable private menuListView: boolean = false;
+ @observable private _ink: boolean = false;
- // private inkDoc?: Doc;
- public drawingInk: boolean = false;
-
- // private uploadDoc?: Doc;
+ public _activeDoc: Doc = this.mainDoc;
+ public _homeDoc: Doc = this.mainDoc;
+ private _homeMenu: boolean = true;
+ private _child: Doc | null = null;
+ private _parents: Array<Doc> = [];
+ private _library: Doc = CurrentUserUtils.setupLibrary(this.userDoc);
constructor(props: Readonly<{}>) {
super(props);
@@ -50,37 +69,35 @@ export default class MobileInterface extends React.Component {
@action
componentDidMount = () => {
- library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer]);
+ Doc.UserDoc().activeMobile = this._homeDoc;
+ this._homeDoc._viewType === "stacking" ? this.menuListView = true : this.menuListView = false;
+ Doc.SetSelectedTool(InkTool.None);
+ this.switchCurrentView((userDoc: Doc) => this._homeDoc);
- if (this.userDoc && !this.mainContainer) {
- this.userDoc.activeMobile = this.mainDoc;
- }
+ document.removeEventListener("dblclick", this.onReactDoubleClick);
+ document.addEventListener("dblclick", this.onReactDoubleClick);
+ }
+
+ // Prevent zooming in when double tapping the screen
+ onReactDoubleClick = (e: MouseEvent) => {
+ e.stopPropagation();
}
+ // Switch the mobile view to the given doc
@action
switchCurrentView = (doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) => {
if (!this.userDoc) return;
- this.userDoc.activeMobile = doc(this.userDoc);
+ Doc.UserDoc().activeMobile = doc(this.userDoc);
onSwitch && onSwitch();
this.renderView = renderView;
}
- onSwitchInking = () => {
- Doc.SetSelectedTool(InkTool.Pen);
- MobileInterface.Instance.drawingInk = true;
-
- DocServer.Mobile.dispatchOverlayTrigger({
- enableOverlay: true,
- width: window.innerWidth,
- height: window.innerHeight
- });
- }
-
onSwitchUpload = async () => {
let width = 300;
let height = 300;
+ const res = await rp.get(Utils.prepend("/getUserDocumentId"));
// get width and height of the collection doc
if (this.mainContainer) {
@@ -102,243 +119,584 @@ export default class MobileInterface extends React.Component {
});
}
- renderDefaultContent = () => {
- if (this.mainContainer) {
- return <DocumentView
- Document={this.mainContainer}
- DataDoc={undefined}
- LibraryPath={emptyPath}
- addDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- rootSelected={returnFalse}
- removeDocument={undefined}
- onClick={undefined}
- ScreenToLocalTransform={Transform.Identity}
- ContentScaling={returnOne}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- PanelWidth={() => window.screen.width}
- PanelHeight={() => window.screen.height}
- renderDepth={0}
- focus={emptyFunction}
- backgroundColor={returnEmptyString}
- parentActive={returnTrue}
- whenActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />;
- }
- return "hello";
- }
+ // For toggling the hamburger menu
+ @action
+ toggleSidebar = () => this.sidebarActive = !this.sidebarActive
- onBack = (e: React.MouseEvent) => {
- this.switchCurrentView((userDoc: Doc) => this.mainDoc);
- Doc.SetSelectedTool(InkTool.None); // TODO: switch to previous tool
+ /**
+ * Method called when 'Library' button is pressed on the home screen
+ */
+ switchToLibrary = () => {
+ this._parents.push(this._activeDoc);
+ this.switchCurrentView((userDoc: Doc) => this._library);
+ this._activeDoc = this._library;
+ this._homeMenu = false;
+ this.sidebarActive = true;
+ }
- DocServer.Mobile.dispatchOverlayTrigger({
- enableOverlay: false,
- width: window.innerWidth,
- height: window.innerHeight
- });
+ /**
+ * Back method for navigating
+ */
+ back = () => {
+ let header = document.getElementById("header") as HTMLElement;
+ let doc = Cast(this._parents.pop(), Doc) as Doc;
- // this.inkDoc = undefined;
- this.drawingInk = false;
+ if (doc === Cast(this._library, Doc) as Doc) {
+ this._child = null;
+ this.userDoc.activeMobile = this._library;
+ } else if (doc === Cast(this._homeDoc, Doc) as Doc) {
+ this._homeMenu = true;
+ this._parents = [];
+ this._activeDoc = this._homeDoc;
+ this._child = null;
+ this.switchCurrentView((userDoc: Doc) => this._homeDoc);
+ } else {
+ if (doc) {
+ this._child = doc;
+ this.switchCurrentView((userDoc: Doc) => doc);
+ this._homeMenu = false;
+ header.textContent = String(doc.title);
+ }
+ }
+ if (doc) {
+ this._activeDoc = doc;
+ }
+ this._ink = false;
}
- shiftLeft = (e: React.MouseEvent) => {
- DocServer.Mobile.dispatchOverlayPositionUpdate({
- dx: -10
- });
- e.preventDefault();
- e.stopPropagation();
+ /**
+ * Return 'Home", which implies returning to 'Home' buttons
+ */
+ returnHome = () => {
+ if (this._homeMenu === false || this.sidebarActive === true) {
+ this._homeMenu = true;
+ this._parents = [];
+ this._activeDoc = this._homeDoc;
+ this._child = null;
+ this.switchCurrentView((userDoc: Doc) => this._homeDoc);
+ }
+ if (this.sidebarActive) {
+ this.toggleSidebar();
+ }
}
- shiftRight = (e: React.MouseEvent) => {
- DocServer.Mobile.dispatchOverlayPositionUpdate({
- dx: 10
- });
- e.preventDefault();
- e.stopPropagation();
+ /**
+ * Return to primary Workspace in library (Workspaces Doc)
+ */
+ returnMain = () => {
+ this._parents = [this._homeDoc];
+ this._activeDoc = this._library;
+ this.switchCurrentView((userDoc: Doc) => this._library);
+ this._homeMenu = false;
+ this._child = null;
}
- panelHeight = () => window.innerHeight;
- panelWidth = () => window.innerWidth;
- renderInkingContent = () => {
- console.log("rendering inking content");
- // TODO: support panning and zooming
- // TODO: handle moving of ink strokes
+ /**
+ * DocumentView for graphic display of all documents
+ */
+ displayWorkspaces = () => {
if (this.mainContainer) {
+ const backgroundColor = () => "white";
return (
- <div className="mobileInterface">
- <div className="mobileInterface-inkInterfaceButtons">
- <div className="navButtons">
- <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing">BACK</button>
- </div>
- <div className="inkSettingButtons">
- <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button>
- </div>
- <div className="navButtons">
- <button className="mobileInterface-button" onClick={this.shiftLeft} title="Shift left">left</button>
- <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button>
- </div>
- </div>
- <CollectionView
+ <div style={{ position: "relative", top: '200px', height: `calc(100% - 200px)`, width: "100%", overflow: "hidden", left: "0%" }}>
+ <DocumentView
Document={this.mainContainer}
DataDoc={undefined}
LibraryPath={emptyPath}
- filterAddDocument={returnTrue}
- fieldKey={""}
- dropAction={"alias"}
- bringToFront={emptyFunction}
+ addDocument={returnFalse}
addDocTab={returnFalse}
pinToPres={emptyFunction}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
+ rootSelected={returnFalse}
+ removeDocument={undefined}
+ onClick={undefined}
+ ScreenToLocalTransform={Transform.Identity}
+ ContentScaling={returnOne}
+ PanelWidth={this.returnWidth}
+ PanelHeight={this.returnHeight}
NativeHeight={returnZero}
NativeWidth={returnZero}
- focus={emptyFunction}
- isSelected={returnFalse}
- select={emptyFunction}
- active={returnFalse}
- ContentScaling={returnOne}
- whenActiveChanged={returnFalse}
- ScreenToLocalTransform={Transform.Identity}
renderDepth={0}
+ focus={emptyFunction}
+ backgroundColor={backgroundColor}
+ parentActive={returnTrue}
+ whenActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
- rootSelected={returnTrue}>
- </CollectionView>
+ />
</div>
);
}
}
- upload = async (e: React.MouseEvent) => {
- if (this.mainContainer) {
- const data = Cast(this.mainContainer.data, listSpec(Doc));
- if (data) {
- const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked
- const children = DocListCast(collectionDoc.data);
- const uploadDoc = children.length === 1 ? children[0] : Docs.Create.StackingDocument(children, {
- title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true, _width: 300, _height: 300
- });
- if (uploadDoc) {
- DocServer.Mobile.dispatchMobileDocumentUpload({
- docId: uploadDoc[Id],
- });
- }
+ returnWidth = () => window.innerWidth; //The windows width
+ returnHeight = () => (window.innerHeight - 300); //Calculating the windows height (-300 to account for topbar)
+
+ /**
+ * Handles the click functionality in the library panel.
+ * Navigates to the given doc and updates the sidebar.
+ * @param doc: doc for which the method is called
+ */
+ handleClick = async (doc: Doc) => {
+ let children = DocListCast(doc.data);
+ if (doc.type !== "collection") {
+ this._parents.push(this._activeDoc);
+ this._activeDoc = doc;
+ this.switchCurrentView((userDoc: Doc) => doc);
+ this._homeMenu = false;
+ this.toggleSidebar();
+ } else if (doc.type === "collection" && children.length === 0) {
+ console.log("This collection has no children");
+ } else {
+ this._parents.push(this._activeDoc);
+ this._activeDoc = doc;
+ this.switchCurrentView((userDoc: Doc) => doc);
+ this._homeMenu = false;
+ this._child = doc;
+ }
+ }
+
+ /**
+ * Handles creation of array which is then rendered in renderPathbar()
+ */
+ createPathname = () => {
+ let docArray = [];
+ this._parents.map((doc: Doc, index: any) => {
+ docArray.push(doc);
+ });
+ docArray.push(this._activeDoc);
+ return docArray;
+ }
+
+ // Renders the graphical pathbar
+ renderPathbar = () => {
+ let docArray = this.createPathname();
+ let items = docArray.map((doc: Doc, index: any) => {
+ if (index === 0) {
+ return (
+ <>
+ {this._homeMenu ?
+ <div className="pathbarItem">
+ <div className="pathbarText"
+ style={{ backgroundColor: "rgb(119, 37, 37)" }}
+ key={index}
+ onClick={() => this.handlePathClick(doc, index)}>{doc.title}
+ </div>
+ </div>
+ :
+ <div className="pathbarItem">
+ <div className="pathbarText"
+ key={index}
+ onClick={() => this.handlePathClick(doc, index)}>{doc.title}
+ </div>
+ </div>}
+ </>);
+
+ } else if (doc === this._activeDoc) {
+ return (
+ <div className="pathbarItem">
+ <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" />
+ <div className="pathbarText"
+ style={{ backgroundColor: "rgb(119, 37, 37)" }}
+ key={index}
+ onClick={() => this.handlePathClick(doc, index)}>{doc.title}
+ </div>
+ </div>);
+ } else {
+ return (
+ <div className="pathbarItem">
+ <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" />
+ <div className="pathbarText"
+ key={index}
+ onClick={() => this.handlePathClick(doc, index)}>{doc.title}
+ </div>
+ </div>);
}
+
+ });
+ if (this._parents.length !== 0) {
+ return (<div className="pathbar">
+ <div className="scrollmenu">
+ {items}
+ </div>
+ <div className="back" >
+ <FontAwesomeIcon onClick={this.back} icon={"chevron-left"} color="white" size={"2x"} />
+ </div>
+ <div className="hidePath" />
+ </div>);
+ } else {
+ return (<div className="pathbar">
+ <div className="scrollmenu">
+ {items}
+ </div>
+ <div className="hidePath" />
+ </div>);
}
- e.stopPropagation();
- e.preventDefault();
}
- addWebToCollection = async () => {
- let url = "https://en.wikipedia.org/wiki/Hedgehog";
- if (this.mainContainer) {
- const data = Cast(this.mainContainer.data, listSpec(Doc));
- if (data) {
- const webDoc = await data[0];
- const urlField: FieldResult<WebField> = Cast(webDoc.data, WebField);
- url = urlField ? urlField.url.toString() : "https://en.wikipedia.org/wiki/Hedgehog";
+ // Handles when user clicks on a document in the pathbar
+ handlePathClick = (doc: Doc, index: number) => {
+ if (doc === this._library) {
+ this._activeDoc = doc;
+ this._child = null;
+ this.switchCurrentView((userDoc: Doc) => doc);
+ this._parents.length = index;
+ } else if (doc === this._homeDoc) {
+ this.returnHome();
+ } else {
+ this._activeDoc = doc;
+ this._child = doc;
+ this.switchCurrentView((userDoc: Doc) => doc);
+ this._parents.length = index;
+ }
+ }
+ // Renders the contents of the menu and sidebar
+ renderDefaultContent = () => {
+ if (this._homeMenu === true) {
+ return (
+ <div>
+ <div className="navbar">
+ <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} />
+ <div className="header" id="header">{this._homeDoc.title}</div>
+ <div className="cover" id="cover" onClick={(e) => this.stop(e)}></div>
+ <div className="toggle-btn" id="menuButton" onClick={this.toggleSidebar}>
+ <span></span>
+ <span></span>
+ <span></span>
+ </div>
+ </div>
+ {this.renderPathbar()}
+ <div className="sidebar" id="sidebar">
+ <div className="sidebarButtons">
+ <div
+ className="item"
+ onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+
+ let workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc;
+ if (this._child) {
+ workspaces = this._child;
+ }
+
+ let buttons = DocListCast(workspaces.data).map((doc: Doc, index: any) => {
+ if (doc.type !== "ink") {
+ return (
+ <div
+ className="item"
+ key={index}
+ onClick={() => this.handleClick(doc)}>{doc.title}
+ <div className="type">{doc.type}</div>
+ <FontAwesomeIcon className="right" icon="angle-right" size="lg" />
+ </div>);
}
+ });
+
+ return (
+ <div>
+ <div className="navbar">
+ <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} />
+ <div className="header" id="header">{this.sidebarActive ? "library" : this._activeDoc.title}</div>
+ <div className={`toggle-btn ${this.sidebarActive ? "active" : ""}`} onClick={this.toggleSidebar}>
+ <span></span>
+ <span></span>
+ <span></span>
+ </div>
+ </div>
+ {this.renderPathbar()}
+ <div className={`sidebar ${this.sidebarActive ? "active" : ""}`}>
+ <div className="sidebarButtons">
+ {this._child ?
+ <>
+ {buttons}
+ <div className="item" key="home" onClick={this.returnMain}>
+ Return to library
+ </div>
+ </> :
+ <>
+ {buttons}
+ <div
+ className="item"
+ onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+ </div>
+ </>
+ }
+ </div>
+ </div>
+ </div>
+ );
+ }
+
+ stop = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ }
+
+ // Button for uploading mobile audio
+ uploadAudioButton = () => {
+ if (this._activeDoc.type === "audio") {
+ return <div className="docButton"
+ title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"}
+ style={{ backgroundColor: "black", color: "white" }}
+ onClick={this.uploadAudio}
+ >
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload"
+ />
+ </div>;
}
- Docs.Create.WebDocument(url, { _width: 300, _height: 300, title: "Mobile Upload Web Doc" });
}
- clearUpload = async () => {
- if (this.mainContainer) {
- const data = Cast(this.mainContainer.data, listSpec(Doc));
- if (data) {
- const collectionDoc = await data[1];
- const children = DocListCast(collectionDoc.data);
- children.forEach(doc => {
- });
- // collectionDoc[data] = new List<Doc>();
+ // Button for switching between pan and ink mode
+ @action
+ onSwitchInking = () => {
+ const button = document.getElementById("inkButton") as HTMLElement;
+ button.style.backgroundColor = this._ink ? "white" : "black";
+ button.style.color = this._ink ? "black" : "white";
+
+ if (!this._ink) {
+ Doc.SetSelectedTool(InkTool.Pen);
+ this._ink = true;
+ } else {
+ Doc.SetSelectedTool(InkTool.None);
+ this._ink = false;
+ }
+ }
+
+ // The static ink menu that appears at the top
+ inkMenu = () => {
+ if (this._activeDoc._viewType === "docking") {
+ if (this._ink) {
+ console.log("here");
+ return <div className="colorSelector">
+ <InkOptionsMenu />
+ </div>
+
}
}
}
- renderUploadContent() {
- if (this.mainContainer) {
+ // Button for switching into ink mode
+ drawInk = () => {
+ if (this._activeDoc._viewType === "docking") {
return (
- <div className="mobileInterface" onDragOver={this.onDragOver}>
- <div className="mobileInterface-inkInterfaceButtons">
- <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
- {/* <button className="mobileInterface-button" onClick={this.clearUpload} title="Clear Upload">CLEAR</button> */}
- {/* <button className="mobileInterface-button" onClick={this.addWeb} title="Add Web Doc to Upload Collection"></button> */}
- <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button>
+ <>
+ <div className="docButton"
+ id="inkButton"
+ title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"}
+ onClick={this.onSwitchInking}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="pen-nib"
+ />
+ </div>
+ </>);
+ }
+ }
+
+ // Button to download images on the mobile
+ downloadDocument = () => {
+ if (this._activeDoc.type === "image") {
+ const url = this._activeDoc["data-path"]?.toString();
+ return <div className="docButton"
+ title={"Download Image"}
+ style={{ backgroundColor: "white", color: "black" }}
+ onClick={e => {
+ window.open(url);
+ console.log(url);
+ }}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="download"
+ />
+ </div>;
+ }
+ }
+
+ // Mobile audio doc
+ recordAudio = async () => {
+ // upload to server with known URL
+ if (this._activeDoc.title !== "mobile audio") {
+ this._parents.push(this._activeDoc);
+ }
+ const audioDoc = Cast(Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100, title: "mobile audio" }), Doc) as Doc;
+ if (audioDoc) {
+ this._activeDoc = audioDoc;
+ this.switchCurrentView((userDoc: Doc) => audioDoc);
+ this._homeMenu = false;
+ }
+ }
+
+ // Pushing the audio doc onto Dash Web through the right side bar
+ uploadAudio = () => {
+ const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc;
+ const audioDoc = this._activeDoc;
+ const data = Cast(audioRightSidebar.data, listSpec(Doc));
+
+ if (data) {
+ data.push(audioDoc);
+ }
+ }
+
+ panelHeight = () => window.innerHeight;
+ panelWidth = () => window.innerWidth;
+
+ // Button for pinning images to presentation
+ pinToPresentation = () => {
+ // Only making button available if it is an image
+ if (this._activeDoc.type === "image") {
+ const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc);
+ return <div className="docButton"
+ title={Doc.isDocPinned(this._activeDoc) ? "Unpin from presentation" : "Pin to presentation"}
+ style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }}
+ onClick={e => {
+ if (isPinned) {
+ DockedFrameRenderer.UnpinDoc(this._activeDoc);
+ }
+ else {
+ DockedFrameRenderer.PinDoc(this._activeDoc);
+ }
+ }}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
+ />
+ </div>;
+ }
+ }
+
+ // Buttons for switching the menu between large and small icons
+ switchMenuView = () => {
+ if (this._activeDoc.title === this._homeDoc.title) {
+ return (
+ <div className="homeSwitch">
+ <div className={`list ${!this.menuListView ? "active" : ""}`} onClick={this.changeToIconView}>
+ <FontAwesomeIcon size="sm" icon="th-large" />
+ </div>
+ <div className={`list ${this.menuListView ? "active" : ""}`} onClick={this.changeToListView}>
+ <FontAwesomeIcon size="sm" icon="bars" />
</div>
- <DocumentView
- Document={this.mainContainer}
- DataDoc={undefined}
- LibraryPath={emptyPath}
- addDocument={returnFalse}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- rootSelected={returnFalse}
- removeDocument={undefined}
- onClick={undefined}
- ScreenToLocalTransform={Transform.Identity}
- ContentScaling={returnOne}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- PanelWidth={() => window.screen.width}
- PanelHeight={() => window.screen.height}
- renderDepth={0}
- focus={emptyFunction}
- backgroundColor={returnEmptyString}
- parentActive={returnTrue}
- whenActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />
</div>
);
}
}
+ // Logics for switching the menu into the icons
+ @action
+ changeToIconView = () => {
+ if (this._homeDoc._viewType = "stacking") {
+ this.menuListView = false;
+ this._homeDoc._viewType = "masonry";
+ this._homeDoc.columnWidth = 300;
+ const menuButtons = DocListCast(this._homeDoc.data);
+ console.log('hello');
+ menuButtons.map((doc: Doc, index: any) => {
+ console.log(index);
+ const buttonData = DocListCast(doc.data);
+ buttonData[1]._nativeWidth = 0.1;
+ buttonData[1]._width = 0.1;
+ buttonData[1]._dimMagnitude = 0;
+ buttonData[1]._opacity = 0;
+ console.log(buttonData);
+ console.log(doc._nativeWidth);
+ doc._nativeWidth = 400;
+ console.log(doc._nativeWidth);
+ });
+ }
+ }
+
+ // Logics for switching the menu into the stacking view
+ @action
+ changeToListView = () => {
+ if (this._homeDoc._viewType = "masonry") {
+ this._homeDoc._viewType = "stacking";
+ this.menuListView = true;
+ const menuButtons = DocListCast(this._homeDoc.data);
+ console.log('hello');
+ menuButtons.map((doc: Doc, index: any) => {
+ const buttonData = DocListCast(doc.data);
+ buttonData[1]._nativeWidth = 450;
+ buttonData[1]._dimMagnitude = 2;
+ buttonData[1]._opacity = 1;
+ console.log(doc._nativeWidth);
+ doc._nativeWidth = 900;
+ console.log(doc._nativeWidth);
+ });
+ }
+ }
+
+ // For setting up the presentation document for the home menu
+ setupDefaultPresentation = () => {
+ if (this._activeDoc.title !== "Presentation") {
+ this._parents.push(this._activeDoc);
+ }
+
+ const presentation = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
+
+ if (presentation) {
+ this._activeDoc = presentation;
+ this.switchCurrentView((userDoc: Doc) => presentation);
+ this._homeMenu = false;
+ }
+ }
+
+ // For toggling image upload pop up
+ @action
+ toggleUpload = () => this.imageUploadActive = !this.imageUploadActive
+
+ // For closing the image upload pop up
+ @action
+ closeUpload = () => {
+ this.imageUploadActive = false;
+ }
+
+ // Returns the image upload pop up
+ uploadImage = () => {
+ if (this.imageUploadActive) {
+ console.log("active");
+ } else if (!this.imageUploadActive) {
+
+ }
+ return (
+ <div>
+ <div className="closeUpload" onClick={this.toggleUpload}>
+ <FontAwesomeIcon icon="window-close" size={"lg"} />
+ </div>
+ <Uploader />
+ </div>
+ );
+ }
+
onDragOver = (e: React.DragEvent) => {
e.preventDefault();
e.stopPropagation();
}
render() {
- // const content = this.currentView === "main" ? this.mainContent :
- // this.currentView === "ink" ? this.inkContent :
- // this.currentView === "upload" ? this.uploadContent : <></>;
return (
<div className="mobileInterface-container" onDragOver={this.onDragOver}>
- {/* <DocumentDecorations />
- <GestureOverlay>
- {this.renderView ? this.renderView() : this.renderDefaultContent()}
- </GestureOverlay> */}
-
- {/* <DictationOverlay />
- <SharingManager />
- <GoogleAuthenticationManager /> */}
- <DocumentDecorations />
+ <SettingsManager />
+ <div className={`image-upload ${this.imageUploadActive ? "active" : ""}`}>
+ {this.uploadImage()}
+ </div>
+ {this.switchMenuView()}
+ <div className="docButtonContainer">
+ {this.pinToPresentation()}
+ {this.downloadDocument()}
+ {this.drawInk()}
+ {this.uploadAudioButton()}
+ </div>
+ {this.inkMenu()}
<GestureOverlay>
- {this.renderView ? this.renderView() : this.renderDefaultContent()}
+ {this.displayWorkspaces()}
+ {this.renderDefaultContent()}
</GestureOverlay>
- <PreviewCursor />
- {/* <ContextMenu /> */}
- <RadialMenu />
- <RichTextMenu />
- {/* <PDFMenu />
- <MarqueeOptionsMenu />
- <OverlayView /> */}
</div>
);
}
}
Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); });
-Scripting.addGlobal(function onSwitchMobileInking() { return MobileInterface.Instance.onSwitchInking(); });
-Scripting.addGlobal(function renderMobileInking() { return MobileInterface.Instance.renderInkingContent(); });
-Scripting.addGlobal(function onSwitchMobileUpload() { return MobileInterface.Instance.onSwitchUpload(); });
-Scripting.addGlobal(function renderMobileUpload() { return MobileInterface.Instance.renderUploadContent(); });
-Scripting.addGlobal(function addWebToMobileUpload() { return MobileInterface.Instance.addWebToCollection(); });
-
+Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); });
+Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); });
+Scripting.addGlobal(function openMobileAudio() { return MobileInterface.Instance.recordAudio(); });
+Scripting.addGlobal(function openMobileSettings() { return SettingsManager.Instance.open(); });
+Scripting.addGlobal(function switchToLibrary() { return MobileInterface.Instance.switchToLibrary(); });
+Scripting.addGlobal(function uploadImageMobile() { return MobileInterface.Instance.toggleUpload(); });
diff --git a/src/mobile/MobileMain.tsx b/src/mobile/MobileMain.tsx
new file mode 100644
index 000000000..3d4680d58
--- /dev/null
+++ b/src/mobile/MobileMain.tsx
@@ -0,0 +1,25 @@
+import { MobileInterface } from "./MobileInterface";
+import { Docs } from "../client/documents/Documents";
+import { CurrentUserUtils } from "../client/util/CurrentUserUtils";
+import * as ReactDOM from 'react-dom';
+import * as React from 'react';
+import { DocServer } from "../client/DocServer";
+import { AssignAllExtensions } from "../extensions/General/Extensions";
+
+AssignAllExtensions();
+
+(async () => {
+ const info = await CurrentUserUtils.loadCurrentUser();
+ DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email + " (mobile)");
+ await Docs.Prototypes.initialize();
+ if (info.id !== "__guest__") {
+ // a guest will not have an id registered
+ await CurrentUserUtils.loadUserDocument(info);
+ }
+ document.getElementById('root')!.addEventListener('wheel', event => {
+ if (event.ctrlKey) {
+ event.preventDefault();
+ }
+ }, true);
+ ReactDOM.render(<MobileInterface />, document.getElementById('root'));
+})(); \ No newline at end of file
diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss
new file mode 100644
index 000000000..8d996f779
--- /dev/null
+++ b/src/mobile/MobileMenu.scss
@@ -0,0 +1,409 @@
+$navbar-height: 120px;
+$pathbar-height: 50px;
+
+* {
+ margin: 0px;
+ padding: 0px;
+ box-sizing: border-box;
+ font-family: "Open Sans";
+}
+
+body {
+ overflow: hidden;
+}
+
+.navbar {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100vw;
+ height: $navbar-height;
+ background-color: whitesmoke;
+ border-bottom: 5px solid black;
+}
+
+.navbar .cover {
+ position: absolute;
+ right: 20px;
+ top: 30px;
+ height: 70px;
+ width: 70px;
+ background-color: whitesmoke;
+ z-index: 200;
+}
+
+.navbar .toggle-btn {
+ position: absolute;
+ right: 20px;
+ top: 30px;
+ height: 70px;
+ width: 70px;
+ transition: all 300ms ease-in-out 200ms;
+}
+
+.navbar .toggle-btn-home {
+ right: -200px;
+}
+
+.navbar .header {
+ position: absolute;
+ top: 50%;
+ top: calc(9px + 50%);
+ right: 50%;
+ transform: translate(50%, -50%);
+ font-size: 40;
+ user-select: none;
+ text-transform: uppercase;
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+.navbar .toggle-btn span {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 70%;
+ height: 4px;
+ background: black;
+ transition: all 200ms ease;
+}
+
+.navbar .toggle-btn span:nth-child(1) {
+ transition: top 200ms ease-in-out;
+ top: 30%;
+}
+
+.navbar .toggle-btn span:nth-child(3) {
+ transition: top 200ms ease-in-out;
+ top: 70%;
+}
+
+.navbar .toggle-btn.active {
+ transition: transform 200ms ease-in-out 200ms;
+ transform: rotate(135deg);
+}
+
+.navbar .toggle-btn.active span:nth-child(1) {
+ top: 50%;
+}
+
+.navbar .toggle-btn.active span:nth-child(2) {
+ transform: translate(-50%, -50%) rotate(90deg);
+}
+
+.navbar .toggle-btn.active span:nth-child(3) {
+ top: 50%;
+}
+
+.sidebar {
+ position: fixed;
+ top: 120px;
+ opacity: 0;
+ right: -100%;
+ width: 100%;
+ height: calc(100% - (120px));
+ z-index: 101;
+ background-color: whitesmoke;
+ transition: all 400ms ease 50ms;
+ padding: 20px;
+ // overflow-y: auto;
+ // -webkit-overflow-scrolling: touch;
+ // border-right: 5px solid black;
+}
+
+.sidebar .item {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 35px;
+ text-transform: uppercase;
+ color: black;
+
+}
+
+.sidebar .ink:focus {
+ outline: 1px solid blue;
+}
+
+.sidebarButtons {
+ top: 80px;
+ position: relative;
+}
+
+.home {
+ position: absolute;
+ top: 30px;
+ left: 30px;
+ font-size: 60;
+ user-select: none;
+ text-transform: uppercase;
+ font-family: Arial, Helvetica, sans-serif;
+ z-index: 200;
+}
+
+.type {
+ display: inline;
+ text-transform: lowercase;
+ margin-left: 20px;
+ font-size: 35px;
+ font-style: italic;
+ color: rgb(28, 28, 28);
+}
+
+.right {
+ margin-left: 20px;
+ z-index: 200;
+}
+
+.left {
+ width: 100%;
+ height: 100%;
+}
+
+.sidebar .logout {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 30px;
+ text-transform: uppercase;
+ color: black;
+}
+
+.sidebar .settings {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 30px;
+ text-transform: uppercase;
+ color: black;
+}
+
+
+.sidebar.active {
+ right: 0%;
+ opacity: 1;
+}
+
+.back {
+ position: absolute;
+ top: 44%;
+ left: 42px;
+ background-color: black;
+ width: 50px;
+ height: 50px;
+ text-align: center;
+ border-radius: 10px;
+ transform: translate(0, -50%);
+ font-size: 25px;
+ user-select: none;
+ z-index: 100;
+}
+
+.pathbar {
+ position: fixed;
+ top: 118px;
+ left: 0px;
+ background: #1a1a1a;
+ z-index: 120;
+ border-radius: 0px;
+ width: 100%;
+ height: 80px;
+ transition: all 400ms ease 50ms;
+}
+
+.pathname {
+ position: relative;
+ font-size: 25;
+ top: 50%;
+ width: 86%;
+ left: 12%;
+ color: whitesmoke;
+ transform: translate(0%, -50%);
+ z-index: 20;
+ font-family: sans-serif;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ direction: rtl;
+ text-align: left;
+ text-transform: uppercase;
+}
+
+.docButton {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ font-size: 70px;
+ padding: 5px;
+ text-align: center;
+ border-style: solid;
+ border-radius: 50px;
+ border-width: 5px;
+ margin: 20px;
+ z-index: 100;
+}
+
+.docButtonContainer {
+ top: 90%;
+ position: absolute;
+ display: flex;
+ transform: translate(-50%, 0);
+ left: 50%;
+ z-index: 100;
+}
+
+.scrollmenu {
+ overflow: auto;
+ white-space: nowrap;
+}
+
+.pathbarItem {
+ position: relative;
+ display: inline-flex;
+ color: whitesmoke;
+ text-align: center;
+ user-select: none;
+ transform: translate(100px, 0px);
+ font-size: 30px;
+ padding: 10px;
+ text-transform: uppercase;
+}
+
+.pathbarText {
+ font-family: sans-serif;
+ text-align: center;
+ height: 50px;
+ padding: 10px;
+ background-color: rgb(48, 40, 40);
+ font-size: 30px;
+ border-radius: 10px;
+ text-transform: uppercase;
+ margin-left: 20px;
+ position: relative;
+}
+
+
+.pathIcon {
+ transform: translate(0px, 8px);
+ position: relative;
+}
+
+.hidePath {
+ position: absolute;
+ height: 100%;
+ width: 200px;
+ left: 0px;
+ top: 0px;
+ background-image: linear-gradient(to right, #1a1a1a, rgba(255, 0, 0, 0));
+ text-align: center;
+ user-select: none;
+ z-index: 99;
+ pointer-events: none;
+}
+
+.toolbar {
+ left: 50%;
+ transform: translate(-50%);
+ position: absolute;
+ height: max-content;
+ top: 0px;
+ border-radius: 20px;
+ background-color: lightgrey;
+ opacity: 0;
+ transition: all 400ms ease 50ms;
+}
+
+.toolbar.active {
+ display: inline-block;
+ width: 300px;
+ padding: 5px;
+ opacity: 1;
+ height: max-content;
+ top: -450px;
+}
+
+.colorSelector {
+ position: absolute;
+ top: 550px;
+ left: 300px;
+ transform: translate(-50%, 0);
+ z-index: 100;
+ display: inline-flex;
+ width: max-content;
+ height: max-content;
+ pointer-events: all;
+ font-size: 90px;
+}
+
+.widthSelector {
+ display: inline-flex;
+ width: max-content;
+ height: 100px;
+ padding: 10px;
+}
+
+.slider {
+ -webkit-appearance: none;
+ /* Override default CSS styles */
+ appearance: none;
+ width: 100%;
+ /* Full-width */
+ height: 25px;
+ /* Specified height */
+ background: #d3d3d3;
+ /* Grey background */
+ outline: none;
+ /* Remove outline */
+}
+
+.colorButton {
+ width: 70px;
+ margin: 10px;
+ height: 70px;
+ border-style: solid;
+ border-width: 3px;
+ border-radius: 100%;
+}
+
+.homeSwitch {
+ position: fixed;
+ top: 212;
+ right: 36px;
+ display: inline-flex;
+ width: max-content;
+ z-index: 99;
+ height: 70px;
+}
+
+.list {
+ width: 70px;
+ height: 70px;
+ margin: 5;
+ padding: 10;
+ align-items: center;
+ text-align: center;
+ font-size: 50;
+ border-style: solid;
+ border-width: 3;
+ border-color: black;
+ background: whitesmoke;
+ align-self: center;
+ border-radius: 10px;
+}
+
+.list.active {
+ color: darkred;
+ border-color: darkred;
+} \ No newline at end of file
diff --git a/src/server/index.ts b/src/server/index.ts
index 590affd06..083173bb5 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -104,6 +104,7 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }:
const serve: PublicHandler = ({ req, res }) => {
const detector = new mobileDetect(req.headers['user-agent'] || "");
const filename = detector.mobile() !== null ? 'mobile/image.html' : 'index.html';
+ console.log(detector.is("iPhone"));
res.sendFile(path.join(__dirname, '../../deploy/' + filename));
};
diff --git a/webpack.config.js b/webpack.config.js
index bd1d3b5a9..a5fe6ad80 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -43,7 +43,7 @@ module.exports = {
repl: ["./src/debug/Repl.tsx", 'webpack-hot-middleware/client?reload=true'],
test: ["./src/debug/Test.tsx", 'webpack-hot-middleware/client?reload=true'],
inkControls: ["./src/mobile/InkControls.tsx", 'webpack-hot-middleware/client?reload=true'],
- imageUpload: ["./src/mobile/ImageUpload.tsx", 'webpack-hot-middleware/client?reload=true'],
+ mobileInterface: ["./src/mobile/MobileMain.tsx", 'webpack-hot-middleware/client?reload=true'],
},
optimization: {
noEmitOnErrors: true
@@ -66,42 +66,42 @@ module.exports = {
},
module: {
rules: [{
- test: [/\.tsx?$/],
- use: [{
- loader: 'ts-loader',
- options: {
- transpileOnly: true
- }
- }]
- },
- {
- test: /\.scss|css$/,
- use: [{
- loader: "style-loader"
+ test: [/\.tsx?$/],
+ use: [{
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true
+ }
+ }]
},
{
- loader: "css-loader"
+ test: /\.scss|css$/,
+ use: [{
+ loader: "style-loader"
+ },
+ {
+ loader: "css-loader"
+ },
+ {
+ loader: "sass-loader"
+ }
+ ]
},
{
- loader: "sass-loader"
+ test: /\.(jpg|png|pdf)$/,
+ use: [{
+ loader: 'file-loader'
+ }]
+ },
+ {
+ test: /\.(png|jpg|gif)$/i,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ limit: 8192
+ }
+ }]
}
- ]
- },
- {
- test: /\.(jpg|png|pdf)$/,
- use: [{
- loader: 'file-loader'
- }]
- },
- {
- test: /\.(png|jpg|gif)$/i,
- use: [{
- loader: 'url-loader',
- options: {
- limit: 8192
- }
- }]
- }
]
},
plugins,