aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/CaptureManager.scss175
-rw-r--r--src/client/util/CaptureManager.tsx140
-rw-r--r--src/client/views/AntimodeMenu.scss14
-rw-r--r--src/client/views/AntimodeMenu.tsx2
-rw-r--r--src/client/views/LightboxView.tsx9
-rw-r--r--src/client/views/MainView.scss3
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/MainViewModal.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.scss126
-rw-r--r--src/client/views/collections/CollectionMenu.tsx76
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx8
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx41
-rw-r--r--src/client/views/nodes/VideoBox.scss10
-rw-r--r--src/client/views/nodes/VideoBox.tsx3
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.scss7
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx2
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx2
18 files changed, 544 insertions, 84 deletions
diff --git a/src/client/util/CaptureManager.scss b/src/client/util/CaptureManager.scss
new file mode 100644
index 000000000..71539ee1e
--- /dev/null
+++ b/src/client/util/CaptureManager.scss
@@ -0,0 +1,175 @@
+@import "../views/globalCssVariables";
+
+.capture-interface {
+ //background-color: whitesmoke !important;
+ width: 450px;
+
+ button {
+ background: #315a96;
+ outline: none;
+ border-radius: 5px;
+ border: 0px;
+ color: #fcfbf7;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ padding: 10px;
+ margin: 10px;
+ transition: transform 0.2s;
+ margin: 2px;
+ }
+}
+
+.capture-t1 {
+ display: flex;
+ justify-content: left;
+ align-items: center;
+ font-size: 20px;
+ font-family: 'Roboto';
+ font-weight: 600;
+ color: black;
+
+ .recordButtonOutline {
+ border-radius: 100%;
+ width: 25px;
+ height: 25px;
+ margin-right: 10px;
+ border: solid 1px #a94442;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .recordButtonInner {
+ border-radius: 100%;
+ width: 70%;
+ height: 70%;
+ background: #a94442;
+ }
+}
+
+.capture-t2 {
+ font-size: 12px;
+ padding-right: 15px;
+ color: black;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ /* right: 135; */
+ // position: absolute;
+ // left: 243;
+}
+
+.capture-block {
+ display: block;
+ padding-bottom: 8px;
+ padding-top: 6px;
+
+ .capture-block-title {
+ font-size: 16;
+ font-weight: bold;
+ text-align: left;
+ color: black;
+ width: 80;
+ margin-right: 50px;
+ margin-bottom: 5px;
+ }
+
+ .capture-block-list {
+ height: 135px;
+ width: calc(100% + 15px);
+ overflow: scroll;
+ }
+
+ .capture-block-radio {
+ font-size: 12;
+ display: block;
+ font-weight: normal;
+
+ .radio-container {
+ display: flex;
+ justify-content: left;
+ align-items: center;
+ font-size: 13px;
+ font-family: 'Roboto';
+ }
+ }
+
+ .list-item {
+ display: flex;
+ height: 25px;
+ font-family: 'Roboto';
+ font-size: 13px;
+
+ .number {
+ width: 20px;
+ height: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #BDDBE8;
+ border-radius: 100%;
+ font-weight: 800;
+ margin-right: 5px;
+ }
+ }
+
+ .buttons {
+ display: flex;
+ position: absolute;
+ bottom: 0;
+ right: 15;
+ justify-content: flex-end;
+ align-items: center;
+ height: 60px;
+
+ .save {
+ cursor: pointer;
+ width: 80px;
+ height: 40px;
+ font-size: 14px;
+ display: flex;
+ font-weight: bold;
+ justify-content: center;
+ align-items: center;
+ background: #337ab7;
+ color: whitesmoke;
+ border-radius: 5px;
+ text-transform: uppercase;
+ }
+
+ .cancel {
+ cursor: pointer;
+ width: 80px;
+ height: 40px;
+ font-size: 14px;
+ display: flex;
+ font-weight: 100;
+ justify-content: center;
+ align-items: center;
+ background: #ccc;
+ color: black;
+ border-radius: 5px;
+ text-transform: uppercase;
+ margin-left: 10px;
+ }
+ }
+}
+
+.close-button {
+ position: absolute;
+ top: 10;
+ right: 10;
+ background:transparent;
+ border-radius:100%;
+ width: 25px;
+ height: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: 0.2s;
+}
+
+.close-button:hover {
+ background: rgba(0,0,0,0.1);
+}
+
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
new file mode 100644
index 000000000..c38337c91
--- /dev/null
+++ b/src/client/util/CaptureManager.tsx
@@ -0,0 +1,140 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { convertToObject } from "typescript";
+import { Doc, DocListCast } from "../../fields/Doc";
+import { BoolCast, StrCast, Cast } from "../../fields/Types";
+import { addStyleSheet, addStyleSheetRule, Utils } from "../../Utils";
+import { LightboxView } from "../views/LightboxView";
+import { MainViewModal } from "../views/MainViewModal";
+import "./CaptureManager.scss";
+import { SelectionManager } from "./SelectionManager";
+import { undoBatch } from "./UndoManager";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+
+@observer
+export class CaptureManager extends React.Component<{}> {
+ public static Instance: CaptureManager;
+ static _settingsStyle = addStyleSheet();
+ @observable _document: any;
+ @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not.
+
+
+ constructor(props: {}) {
+ super(props);
+ CaptureManager.Instance = this;
+ }
+
+ public close = action(() => this.isOpen = false);
+ public open = action((doc: Doc) => {
+ this.isOpen = true;
+ this._document = doc;
+ });
+
+
+ @computed get visibilityContent() {
+
+ return <div className="capture-block">
+ <div className="capture-block-title">Visibility</div>
+ <div className="capture-block-radio">
+ <div className="radio-container">
+ <input type="radio" value="private" name="visibility" style={{ margin: 0, marginRight: 5 }} /> Private
+ </div>
+ <div className="radio-container">
+ <input type="radio" value="public" name="visibility" style={{ margin: 0, marginRight: 5 }} /> Public
+ </div>
+ </div>
+ </div>;
+ }
+
+ @computed get linksContent() {
+ const doc = this._document;
+ const order: JSX.Element[] = [];
+ if (doc) {
+ console.log('title', doc.title);
+ console.log('links', doc.links);
+ const linkDocs = DocListCast(doc.links);
+ const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor1
+ const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor2
+ linkDocs.forEach((l, i) => {
+ if (l) {
+ console.log(i, (l.anchor1 as Doc).title);
+ console.log(i, (l.anchor2 as Doc).title);
+ order.push(
+ <div className="list-item">
+ <div className="number">{i}</div>
+ {(l.anchor1 as Doc).title}
+ </div>
+ );
+ }
+ });
+ }
+
+ return <div className="capture-block">
+ <div className="capture-block-title">Links</div>
+ <div className="capture-block-list">
+ {order}
+ </div>
+ </div>;
+ }
+
+ @computed get closeButtons() {
+ return <div className="capture-block">
+ <div className="buttons">
+ <div className="save" onClick={() => {
+ LightboxView.SetLightboxDoc(this._document);
+ this.close();
+ }}>
+ Save
+ </div>
+ <div className="cancel" onClick={() => {
+ const selected = SelectionManager.Views().slice();
+ SelectionManager.DeselectAll();
+ selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
+ this.close();
+ }}>
+ Cancel
+ </div>
+ </div>
+ </div>
+ }
+
+
+
+ private get captureInterface() {
+ return <div className="capture-interface">
+ <div className="capture-t1">
+ <div className="recordButtonOutline" style={{}}>
+ <div className="recordButtonInner" style={{}}>
+ </div>
+ </div>
+ Conversation Capture
+ </div>
+ <div className="capture-t2">
+
+ </div>
+ {this.visibilityContent}
+ {this.linksContent}
+ <div className="close-button" onClick={this.close}>
+ <FontAwesomeIcon icon={"times"} color="black" size={"lg"} />
+ </div>
+ {this.closeButtons}
+ </div>;
+
+ }
+
+ render() {
+ return <MainViewModal
+ contents={this.captureInterface}
+ isDisplayed={this.isOpen}
+ interactive={true}
+ closeOnExternalClick={this.close}
+ dialogueBoxStyle={{ width: "500px", height: "350px", border: "none", background: "whitesmoke" }}
+ overlayStyle={{ background: "black" }}
+ overlayDisplayedOpacity={0.6}
+ />
+ }
+} \ No newline at end of file
diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss
index c9b5e7658..a275901be 100644
--- a/src/client/views/AntimodeMenu.scss
+++ b/src/client/views/AntimodeMenu.scss
@@ -7,7 +7,7 @@
height: $antimodemenu-height;
background: #323232;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
- border-radius: 0px 6px 6px 6px;
+ // border-radius: 0px 6px 6px 6px;
z-index: 1001;
display: flex;
@@ -24,6 +24,16 @@
background-color: transparent;
width: 35px;
height: 35px;
+ padding: 5;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+
+ .svg {
+ margin: 0;
+ }
&.active {
background-color: #121212;
@@ -31,7 +41,7 @@
}
.antimodeMenu-button:hover {
- background-color: #121212;
+ background-color: rgba(0, 0, 0, 0.4);
}
.antimodeMenu-dragger {
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index 5acb3e4c8..fe6d39ca4 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -140,7 +140,7 @@ export abstract class AntimodeMenu<T extends AntimodeMenuProps> extends React.Co
left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay,
position: this.Pinned ? "unset" : undefined
}}>
- <div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: "20px" }} />
+ {/* {this.getDragger} */}
{buttons}
</div>
);
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index b26765fa7..098c40df4 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -188,9 +188,14 @@ export class LightboxView extends React.Component<LightboxViewProps> {
LightboxView._future?.push(...DocListCast(tours[0][fieldKey]).reverse());
} else {
const coll = LightboxView._docTarget;
- if (coll) {
+ const doc = LightboxView.LightboxDoc;
+ if (coll && doc) {
+ console.log('test');
+ console.log('target: ' + coll.title);
+ console.log('doc: ' + doc.title);
const fieldKey = Doc.LayoutFieldKey(coll);
- LightboxView.SetLightboxDoc(coll, undefined, [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + "-annotations"])]);
+ LightboxView.SetLightboxDoc(doc);
+ // LightboxView.SetLightboxDoc(coll, undefined, [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + "-annotations"])]);
TabDocView.PinDoc(coll, { hidePresBox: true });
}
}
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 8ccb64744..3f04a0f3a 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -358,9 +358,6 @@
.mainView-libraryFlyout-out {
transition: width .25s;
box-shadow: rgb(156, 147, 150) 0.2vw 0.2vw 0.2vw;
- .mainView-docButtons {
- left: 0;
- }
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 204ec370f..7d78d74e3 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -17,6 +17,7 @@ import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, return
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { Docs, DocUtils } from '../documents/Documents';
+import { CaptureManager } from '../util/CaptureManager';
import { CurrentUserUtils } from '../util/CurrentUserUtils';
import { DocumentManager } from '../util/DocumentManager';
import { GroupManager } from '../util/GroupManager';
@@ -177,8 +178,8 @@ export class MainView extends React.Component {
const targClass = targets[0].className.toString();
if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) {
const check = targets.some((thing) =>
- (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
- thing.className === "collectionSchema-header-menuOptions"));
+ (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
+ thing.className === "collectionSchema-header-menuOptions"));
!check && SearchBox.Instance.resetSearch(true);
}
!targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu();
@@ -619,6 +620,7 @@ export class MainView extends React.Component {
<DictationOverlay />
<SharingManager />
<SettingsManager />
+ <CaptureManager />
<GroupManager />
<GoogleAuthenticationManager />
<DocumentDecorations boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index 7f91c0079..55dee005d 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -34,7 +34,7 @@ export class MainViewModal extends React.Component<MainViewOverlayProps> {
<div className="overlay"
onClick={this.props?.closeOnExternalClick}
style={{
- backgroundColor: "gainsboro",
+ backgroundColor: "black",
...(p.overlayStyle || {}),
opacity: p.isDisplayed ? overlayOpacity : 0
}}
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 2c81d727e..9eac75f4b 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -14,35 +14,53 @@
top: 0;
width: 100%;
- .antimodeMenu-button {
- padding: 0;
- width: 30px;
+ .recordButtonOutline {
+ border-radius: 100%;
+ width: 18px;
+ height: 18px;
+ border: solid 1px #f5f5f5;
display: flex;
+ align-items: center;
+ justify-content: center;
+ }
- svg {
- margin: auto;
- }
+ .recordButtonInner {
+ border-radius: 100%;
+ width: 70%;
+ height: 70%;
+ background: white;
}
.collectionMenu {
display: flex;
- padding-bottom: 1px;
- height: 32px;
- border-bottom: .5px solid rgb(180, 180, 180);
+ height: 100%;
overflow: visible;
z-index: 901;
border: unset;
+ .collectionMenu-divider {
+ height: 85%;
+ margin-left: 3px;
+ margin-right: 3px;
+ width: 1.5px;
+ background-color: #656060;
+ }
+
.collectionViewBaseChrome {
display: flex;
+ align-items: center;
.collectionViewBaseChrome-viewPicker {
font-size: 75%;
- background: #323232;
outline-color: black;
color: white;
border: none;
- border-right: solid gray 1px;
+ background: #323232;
+ }
+
+ .collectionViewBaseChrome-viewPicker:focus {
+ outline: none;
+ border: none;
}
.collectionViewBaseChrome-viewPicker:active {
@@ -65,18 +83,26 @@
margin-left: 3px;
margin-right: 0px;
font-size: 75%;
- background: #323232;
+ text-transform: capitalize;
color: white;
border: none;
- border-right: solid gray 1px;
+ background: #323232;
+ }
+
+ .collectionViewBaseChrome-cmdPicker:focus {
+ border: none;
+ outline: none;
}
.commandEntry-outerDiv {
pointer-events: all;
- background-color: #323232;
+ background-color: transparent;
display: flex;
flex-direction: row;
- height: 30px;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ overflow: hidden;
.commandEntry-drop {
color: white;
@@ -86,6 +112,15 @@
}
}
+ .commandEntry-outerDiv:hover{
+ background-color: rgba(0,0,0,0.2);
+
+ .collectionViewBaseChrome-viewPicker,
+ .collectionViewBaseChrome-cmdPicker{
+ background: rgb(41,41,41);
+ }
+ }
+
.collectionViewBaseChrome-collapse {
transition: all .5s, opacity 0.3s;
position: absolute;
@@ -103,11 +138,12 @@
.collectionViewBaseChrome-template,
.collectionViewBaseChrome-viewModes {
- display: grid;
- background: rgb(238, 238, 238);
+ align-items: center;
+ height: 100%;
+ display: flex;
+ background: transparent;
color: grey;
- margin-top: auto;
- margin-bottom: auto;
+ justify-content: center;
}
.collectionViewBaseChrome-viewSpecs {
@@ -263,27 +299,52 @@
.collectionTreeViewChrome-pivotField-cont,
.collection3DCarouselViewChrome-scrollSpeed-cont {
justify-self: right;
- display: flex;
+ align-items: center;
+ display: grid;
+ grid-auto-columns: auto;
font-size: 75%;
letter-spacing: 2px;
.collectionStackingViewChrome-pivotField-label,
.collectionTreeViewChrome-pivotField-label,
.collection3DCarouselViewChrome-scrollSpeed-label {
- vertical-align: center;
- padding-left: 10px;
- margin: auto;
+ grid-column: 1;
+ margin-right: 7px;
+ user-select: none;
+ font-family: 'Roboto';
+ letter-spacing: normal;
+ }
+
+ .collectionStackingViewChrome-sortIcon {
+ transition: transform .5s;
+ grid-column: 3;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ width: 25px;
+ height: 25px;
+ border-radius: 100%;
+ }
+
+ .collectionStackingViewChrome-sortIcon:hover {
+ background-color: rgba(0,0,0,0.2);
}
.collectionStackingViewChrome-pivotField,
.collectionTreeViewChrome-pivotField,
.collection3DCarouselViewChrome-scrollSpeed {
color: white;
- width: 100%;
+ grid-column: 2;
+ grid-row: 1;
+ width: 90%;
min-width: 100px;
display: flex;
+ height: 80%;
+ border-radius: 7px;
align-items: center;
- background: rgb(238, 238, 238);
+ background: #eeeeee;
.editable-view-input,
input,
@@ -378,20 +439,13 @@
display: inline-flex;
position: relative;
align-items: center;
- margin-left: 10px;
-
- .antimodeMenu-button {
- text-align: center;
- display: block;
- position: relative;
- }
+ height: 100%;
.color-previewI {
- width: 80%;
- height: 20%;
- bottom: 0;
+ width: 60%;
+ top: 80%;
position: absolute;
- margin-left: 2px;
+ height: 4px;
}
.color-previewII {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 623e05b33..f56f12c67 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -15,7 +15,7 @@ import { RichTextField } from "../../../fields/RichTextField";
import { listSpec } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
+import { DeepCopy, emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { DragManager } from "../../util/DragManager";
@@ -34,6 +34,9 @@ import "./CollectionMenu.scss";
import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
import { TabDocView } from "./TabDocView";
import { LightboxView } from "../LightboxView";
+import { Docs } from "../../documents/Documents";
+import { DocumentManager } from "../../util/DocumentManager";
+import { CollectionDockingView } from "./CollectionDockingView";
@observer
export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -388,7 +391,32 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
return !targetDoc ? (null) : <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div>} placement="top">
<button className="antimodeMenu-button" style={{ backgroundColor: isPinned ? "121212" : undefined, borderLeft: "1px solid gray" }}
onClick={e => TabDocView.PinDoc(targetDoc, { unpin: isPinned })}>
- <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin" />
+ <FontAwesomeIcon className="colMenu-icon" size="lg" icon="map-pin" />
+ </button>
+ </Tooltip>;
+ }
+
+ @undoBatch
+ @action
+ startRecording = () => {
+ const doc = Docs.Create.ScreenshotDocument("", { _fitWidth: true, _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List<string>(["system"]) });
+ doc.x = 0;
+ doc.y = 0;
+ doc.startRec = true;
+ //Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc);
+ CollectionDockingView.AddSplit(doc, "right");
+ }
+
+ @computed
+ get recordButton() {
+ const targetDoc = this.selectedDoc;
+ return <Tooltip key="record" title={<div className="dash-tooltip">{"Capture screen"}</div>} placement="top">
+ <button className="antimodeMenu-button"
+ onClick={e => this.startRecording()}>
+ <div className="recordButtonOutline" style={{}}>
+ <div className="recordButtonInner" style={{}}>
+ </div>
+ </div>
</button>
</Tooltip>;
}
@@ -478,7 +506,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
const targetDoc = this.selectedDoc;
return !targetDoc || targetDoc.type === DocumentType.PRES ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
<button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
- <FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />
+ <FontAwesomeIcon className="colMenu-icon" icon="copy" size="lg" />
</button>
</Tooltip>;
}
@@ -486,38 +514,48 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get lightboxButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"View in Lightbox"}</div>} placement="top">
- <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", justifyContent: 'center' }} onPointerDown={() => {
+ <button className="antimodeMenu-button" onPointerDown={() => {
const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
LightboxView.SetLightboxDoc(targetDoc, undefined, docs);
}}>
- <FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
+ <FontAwesomeIcon className="colMenu-icon" icon="desktop" size="lg" />
</button>
</Tooltip>;
}
+ @computed get toggleOverlayButton() {
+ return <>
+ <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom">
+ <button className={"antimodeMenu-button"} key="float"
+ style={{
+ backgroundColor: this.props.docView.layoutDoc.z ? "121212" : undefined,
+ pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "none" : undefined,
+ color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "dimgrey" : undefined
+ }}
+ onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
+ <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
+ </button>
+ </Tooltip>
+ </>
+ }
+
render() {
return (
<div className="collectionMenu-cont" >
<div className="collectionMenu">
<div className="collectionViewBaseChrome">
+ {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
+ <div className="collectionMenu-divider" key="divider1"></div>
{this.aliasButton}
{/* {this.pinButton} */}
+ {this.toggleOverlayButton}
{this.pinWithViewButton}
- {this.lightboxButton}
- <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom">
- <button className={"antimodeMenu-button"} key="float"
- style={{
- backgroundColor: this.props.docView.layoutDoc.z ? "121212" : undefined, borderRight: "1px solid gray",
- pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "none" : undefined,
- color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? "dimgrey" : undefined
- }}
- onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
- <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
- </button>
- </Tooltip>
+ <div className="collectionMenu-divider" key="divider2"></div>
{this.subChrome}
- {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
- {!this._buttonizableCommands ? (null) : this.templateChrome}
+ <div className="collectionMenu-divider" key="divider3"></div>
+ {this.lightboxButton}
+ {this.recordButton}
+ {/* {!this._buttonizableCommands ? (null) : this.templateChrome} */}
</div>
</div>
</div>
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 6a1242f20..4f9f297a2 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -234,15 +234,15 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
return level;
}
- dictationHeight = () => this.props.PanelHeight() / 3;
- timelineContentHeight = () => this.props.PanelHeight() * 2 / 3;
+ dictationHeight = () => "50%";
+ timelineContentHeight = () => this.props.PanelHeight() / 2;
dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight());
@computed get renderDictation() {
const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
- return !dictation ? (null) : <div style={{ position: "absolute", height: this.dictationHeight(), top: this.timelineContentHeight(), background: "tan" }}>
+ return !dictation ? (null) : <div style={{ position: "absolute", height: this.dictationHeight(), top: "50%", background: "tan" }}>
<DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
Document={dictation}
- PanelHeight={this.dictationHeight}
+ PanelHeight={() => "100%"}
isAnnotationOverlay={true}
isDocumentActive={returnFalse}
select={emptyFunction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 22543cc8a..859aff2e8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1106,7 +1106,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
position: this.props.Document.isInkMask ? "absolute" : undefined,
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: xshift() ?? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%`,
- height: yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
+ height: this.props.Document.type === DocumentType.VID ? "100%" : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` :
`${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`),
}}>
<DocumentViewInternal {...this.props}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 8163b652c..cecc593f0 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,6 +1,6 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import { DateField } from "../../../fields/DateField";
import { Doc, WidthSym } from "../../../fields/Doc";
@@ -25,6 +25,7 @@ import "./ScreenshotBox.scss";
import { VideoBox } from "./VideoBox";
import { TraceMobx } from "../../../fields/util";
import { FormattedTextBox } from "./formattedText/FormattedTextBox";
+import { CaptureManager } from "../../util/CaptureManager";
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
}
@@ -35,11 +36,13 @@ const ScreenshotDocument = makeInterface(documentSchema);
@observer
export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
- private _videoRef = React.createRef<HTMLVideoElement>();
+ private _videoRef: HTMLVideoElement | undefined | null;
private _audioRec: any;
private _videoRec: any;
@observable _screenCapture = false;
@computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
+ private _disposers: { [name: string]: IReactionDisposer } = {};
+
constructor(props: any) {
super(props);
@@ -53,7 +56,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
videoLoad = () => {
- const aspect = this._videoRef.current!.videoWidth / this._videoRef.current!.videoHeight;
+ const aspect = this._videoRef!.videoWidth / this._videoRef!.videoHeight;
const nativeWidth = Doc.NativeWidth(this.layoutDoc);
const nativeHeight = Doc.NativeHeight(this.layoutDoc);
if (!nativeWidth || !nativeHeight) {
@@ -70,6 +73,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
componentWillUnmount() {
const ind = DocUtils.ActiveRecordings.indexOf(this);
ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
+ Object.values(this._disposers).forEach(disposer => disposer?.());
}
specificContextMenu = (e: React.MouseEvent): void => {
@@ -78,10 +82,22 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
@computed get content() {
+ trace();
+ console.log('content');
const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
- return <video className={"videoBox-content" + interactive} key="video" ref={this._videoRef}
- autoPlay={this._screenCapture}
- style={{ width: this._screenCapture ? "100%" : undefined, height: this._screenCapture ? "100%" : undefined }}
+ return <video className={"videoBox-content" + interactive} key="video"
+ ref={r => {
+ console.log('ref: ', r);
+ this._videoRef = r;
+ setTimeout(() => {
+ if (this.rootDoc.startRec && this._videoRef) { // TODO glr: use mediaState
+ this.toggleRecording();
+ this.rootDoc.startRec = undefined;
+ }
+ }, 1000);
+ }}
+ autoPlay={true}
+ style={{ width: "100%", height: "100%" }}
onCanPlay={this.videoLoad}
controls={true}
onClick={e => e.preventDefault()}>
@@ -91,8 +107,12 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
toggleRecording = action(async () => {
+ console.log("toggleRecording");
+ console.log("2:" + this._videoRef!.srcObject);
+
this._screenCapture = !this._screenCapture;
if (this._screenCapture) {
+ console.log("opening");
this._audioRec = new MediaRecorder(await navigator.mediaDevices.getUserMedia({ audio: true }));
const aud_chunks: any = [];
this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
@@ -102,12 +122,13 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client));
}
};
- this._videoRef.current!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
- this._videoRec = new MediaRecorder(this._videoRef.current!.srcObject);
+ this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
+ this._videoRec = new MediaRecorder(this._videoRef!.srcObject);
const vid_chunks: any = [];
this._videoRec.onstart = () => this.dataDoc[this.props.fieldKey + "-recordingStart"] = new DateField(new Date());
this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data);
this._videoRec.onstop = async (e: any) => {
+ console.log("onStop: video end");
const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() });
const [{ result }] = await Networking.UploadFilesToServer(file);
this.dataDoc[this.fieldKey + "-duration"] = (new Date().getTime() - this.recordingStart!) / 1000;
@@ -129,6 +150,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this.dataDoc.mediaState = "paused";
const ind = DocUtils.ActiveRecordings.indexOf(this);
ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
+
+ CaptureManager.Instance.open(this.rootDoc);
+ console.log("closing");
}
});
@@ -149,6 +173,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
render() {
TraceMobx();
+ console.log('rendering');
return <div className="videoBox" onContextMenu={this.specificContextMenu} style={{ width: "100%", height: "100%" }} >
<div className="videoBox-viewer" >
<div style={{ position: "relative", height: this.videoPanelHeight() }}>
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index dd8d77603..30f0c4393 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,3 +1,13 @@
+.mini-viewer{
+ cursor: grab;
+ position: absolute;
+ right: 10;
+ top: 10;
+ opacity: 0.1;
+ transition: all 0.4s;
+ color: white;
+}
+
.videoBox {
transform-origin: top left;
width: 100%;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fb58ddefc..ab072a97f 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -417,12 +417,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
onTimelineHdlDown = action((e: React.PointerEvent) => {
this._clicking = true;
+ console.log('timeline click');
setupMoveUpEvents(this, e,
action((e: PointerEvent) => {
this._clicking = false;
if (this.isContentActive()) {
const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY);
- this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100));
+ this.layoutDoc._timelineHeightPercent = 50;
}
return false;
}), emptyFunction,
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.scss b/src/client/views/nodes/formattedText/RichTextMenu.scss
index fbc468292..1d24d6833 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.scss
+++ b/src/client/views/nodes/formattedText/RichTextMenu.scss
@@ -95,9 +95,10 @@
.color-preview-button {
.color-preview {
- width: 100%;
- height: 3px;
- margin-top: 3px;
+ width: 60%;
+ top: 80%;
+ position: absolute;
+ height: 4px;
}
}
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 5da868281..071491463 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -976,7 +976,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const row2 = <div className="antimodeMenu-row row-2" key="row2">
{this.collapsed ? this.getDragger() : (null)}
<div key="row 2" style={{ display: this.collapsed ? "none" : undefined }}>
- <div className="richTextMenu-divider" key="divider 3" />,
+ <div className="richTextMenu-divider" key="divider 3" />
{[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => {
this.activeFontSize = val;
SelectionManager.Views().map(dv => dv.props.Document._fontSize = val);
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index a1fc77a92..f15d51764 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -57,6 +57,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
@computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
componentDidMount() {
+ this.layoutDoc.hideLinkButton = true;
this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
}
@@ -114,6 +115,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
searchFilterDocs={this.props.searchFilterDocs}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
+ hideLinkButton={true}
/>
<div className="presItem-embeddedMask" />
</div>;