aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts9
-rw-r--r--src/client/util/CaptureManager.scss175
-rw-r--r--src/client/util/CaptureManager.tsx140
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/views/AntimodeMenu.scss14
-rw-r--r--src/client/views/AntimodeMenu.tsx2
-rw-r--r--src/client/views/DocComponent.tsx4
-rw-r--r--src/client/views/MainView.scss3
-rw-r--r--src/client/views/MainView.tsx8
-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.tsx71
-rw-r--r--src/client/views/collections/CollectionPileView.tsx13
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx11
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/AudioBox.tsx2
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/PresBox.tsx43
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx29
-rw-r--r--src/client/views/nodes/VideoBox.scss10
-rw-r--r--src/client/views/nodes/WebBox.tsx25
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
-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/pdf/PDFViewer.tsx3
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx2
-rw-r--r--src/fields/Doc.ts2
33 files changed, 593 insertions, 130 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3e05787bf..219890945 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -164,6 +164,7 @@ export class DocumentOptions {
version?: string; // version identifier for a document
label?: string;
hidden?: boolean;
+ mediaState?: string; // status of media document: "pendingRecording", "recording", "paused", "playing"
autoPlayAnchors?: boolean; // whether to play audio/video when an anchor is clicked in a stackedTimeline.
dontPlayLinkOnSelect?: boolean; // whether an audio/video should start playing when a link is followed to it.
toolTip?: string; // tooltip to display on hover
@@ -703,8 +704,8 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.WEBCAM), "", options);
}
- export function ScreenshotDocument(url: string, options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", options);
+ export function ScreenshotDocument(title: string, options: DocumentOptions = {}) {
+ return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", { ...options, title });
}
export function ComparisonDocument(options: DocumentOptions = { title: "Comparison Box" }) {
@@ -1340,7 +1341,7 @@ export namespace DocUtils {
}
}
- export function LeavePushpin(doc: Doc) {
+ export function LeavePushpin(doc: Doc, annotationField: string) {
if (doc.isPushpin) return undefined;
const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null);
const hasContextAnchor = DocListCast(doc.links).
@@ -1353,7 +1354,7 @@ export namespace DocUtils {
icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), backgroundColor: "#ACCEF7",
_width: 15, _height: 15, _xPadding: 0, _isLinkButton: true, _timecodeToShow: Cast(doc._timecodeToShow, "number", null)
});
- Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin);
+ Doc.AddDocToList(context, annotationField, pushpin);
const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", "");
doc._timecodeToShow = undefined;
return pushpin;
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/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 0875d9be7..cb8bf5a7f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -423,7 +423,7 @@ export class CurrentUserUtils {
((doc.emptyScript as Doc).proto as Doc)["dragFactory-count"] = 0;
}
if (doc.emptyScreenshot === undefined) {
- doc.emptyScreenshot = Docs.Create.ScreenshotDocument("", { _fitWidth: true, _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List<string>(["system"]) });
+ doc.emptyScreenshot = Docs.Create.ScreenshotDocument("empty screenshot", { _fitWidth: true, _width: 400, _height: 200, system: true, cloneFieldFilter: new List<string>(["system"]) });
}
if (doc.emptyAudio === undefined) {
doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "audio recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
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/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 5ff96ac8d..c017b7015 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -151,7 +151,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
if (toRemove.length !== 0) {
const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc;
toRemove.forEach(doc => {
- leavePushpin && DocUtils.LeavePushpin(doc);
+ leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
doc.context = undefined;
recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
@@ -216,7 +216,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
else {
added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document
this.props.layerProvider?.(doc, true);
- DocUtils.LeavePushpin(doc);
+ //DocUtils.LeavePushpin(doc);
doc._stayInCollection = undefined;
doc.context = this.props.Document;
if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document;
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 19a2eb1b4..fa2a738c8 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';
@@ -274,7 +275,11 @@ export class MainView extends React.Component {
@computed get dockingContent() {
return <div key="docking" className={`mainContent-div${this._flyoutWidth ? "-flyout" : ""}`} onDrop={e => { e.stopPropagation(); e.preventDefault(); }}
- style={{ minWidth: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`, width: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)` }}>
+ style={{
+ minWidth: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`,
+ transform: LightboxView.LightboxDoc ? "scale(0.0001)" : undefined,
+ width: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`
+ }}>
{!this.mainContainer ? (null) : this.mainDocView}
</div>;
}
@@ -621,6 +626,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..a26953ff6 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -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,29 @@ 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("screen recording", { _fitWidth: true, _width: 400, _height: 200, mediaState: "pendingRecording" });
+ //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 +503,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 +511,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/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 6f6cdd5d2..6baf633dd 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -2,7 +2,7 @@ import { action, computed } from "mobx";
import { observer } from "mobx-react";
import { Doc, HeightSym, WidthSym } from "../../../fields/Doc";
import { NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, setupMoveUpEvents } from "../../../Utils";
+import { emptyFunction, setupMoveUpEvents, returnTrue } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { SelectionManager } from "../../util/SelectionManager";
import { SnappingManager } from "../../util/SnappingManager";
@@ -31,9 +31,16 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
// returns the contents of the pileup in a CollectionFreeFormView
@computed get contents() {
+ const isStarburst = this.layoutEngine() === "starburst";
const draggingSelf = this.props.isSelected();
- return <div className="collectionPileView-innards" style={{ pointerEvents: this.layoutEngine() === "starburst" || (SnappingManager.GetIsDragging() && !draggingSelf) ? undefined : "none", zIndex: this.layoutEngine() === "starburst" && !SnappingManager.GetIsDragging() ? -10 : "auto" }} >
- <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine}
+ return <div className="collectionPileView-innards"
+ style={{
+ pointerEvents: isStarburst || (SnappingManager.GetIsDragging() && !draggingSelf) ? undefined : "none",
+ zIndex: isStarburst && !SnappingManager.GetIsDragging() ? -10 : "auto"
+ }} >
+ <CollectionFreeFormView {...this.props}
+ layoutEngine={this.layoutEngine}
+ childDocumentsActive={isStarburst ? returnTrue : undefined}
addDocument={undoBatch((doc: Doc | Doc[]) => {
(doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d));
return this.props.addDocument?.(doc) || false;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 6a1242f20..ab9c4aa2c 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -234,8 +234,9 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
return level;
}
- dictationHeight = () => this.props.PanelHeight() / 3;
- timelineContentHeight = () => this.props.PanelHeight() * 2 / 3;
+ dictationHeightPercent = 50;
+ dictationHeight = () => `${this.dictationHeightPercent}%`;
+ timelineContentHeight = () => this.props.PanelHeight() * this.dictationHeightPercent / 100;
dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight());
@computed get renderDictation() {
const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
@@ -348,7 +349,11 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
(time) => {
const dictationDoc = Cast(this.props.layoutDoc["data-dictation"], Doc, null);
const isDictation = dictationDoc && DocListCast(this.props.mark.links).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc);
- if ((isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this.props.layoutDoc)) && DocListCast(this.props.mark.links).length &&
+ if (!LightboxView.LightboxDoc
+ // bcz: when should links be followed? we don't want to move away from the video to follow a link but we can open it in a sidebar/etc. But we don't know that upfront.
+ // for now, we won't follow any links when the lightbox is oepn to avoid "losing" the video.
+ /*(isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this.props.layoutDoc))*/
+ && DocListCast(this.props.mark.links).length &&
time > NumCast(this.props.mark[this.props.startTag]) &&
time < NumCast(this.props.mark[this.props.endTag]) &&
this._lastTimecode < NumCast(this.props.mark[this.props.startTag])) {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8d8c69fd5..1aed40bc3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -55,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@computed get chromeHidden() { return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); }
@computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField), null); }
@computed get pivotField() { return StrCast(this.layoutDoc._pivotField); }
- @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); }
+ @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); }
@computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); }
@computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
@computed get yMargin() { return this.props.yMargin || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index bee7aeb87..47733994b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -235,7 +235,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
}
});
const pt = this.props.screenToLocalTransform().inverse().transformPoint(x, y);
- ContextMenu.Instance.displayMenu(x, y);
+ ContextMenu.Instance.displayMenu(x, y, undefined, true);
}
@computed get innards() {
TraceMobx();
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index b998555d8..a5d62acb4 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -74,7 +74,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const { Document, DataDoc } = this.props;
const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys
- return pair.layout && !pair.layout.hidden && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
+ return pair.layout && /*!pair.layout.hidden &&*/ (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
});
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4dc0ee3e6..85ae66fdc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -66,6 +66,7 @@ export interface CollectionViewProps extends FieldViewProps {
// property overrides for child documents
children?: never | (() => JSX.Element[]) | React.ReactNode;
childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
+ childDocumentsActive?: () => boolean;// whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode)
childFitWidth?: () => boolean;
childOpacity?: () => number;
childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c623ce653..7a879ecde 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1032,7 +1032,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
docRangeFilters={this.freeformRangeDocFilters}
searchFilterDocs={this.searchFilterDocs}
isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse}
- isDocumentActive={this.isContentActive}
+ isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
focus={this.focusDocument}
addDocTab={this.addDocTab}
addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 85899578c..a2e36f12e 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -53,7 +53,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@observable _position: number = 0;
@observable _waveHeight: Opt<number> = this.layoutDoc._height;
@observable _paused: boolean = false;
- @computed get mediaState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.mediaState as (undefined | "recording" | "paused" | "playing"); }
+ @computed get mediaState(): undefined | "pendingRecording" | "recording" | "paused" | "playing" { return this.dataDoc.mediaState as (undefined | "pendingRecording" | "recording" | "paused" | "playing"); }
set mediaState(value) { this.dataDoc.mediaState = value; }
public static SetScrubTime = action((timeInMillisFrom1970: number) => { AudioBox._scrubTime = 0; AudioBox._scrubTime = timeInMillisFrom1970; });
@computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0fc7a752f..4f4df32b3 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -20,6 +20,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
select: (isCtrlPressed: boolean) => void;
isContentActive: (outsideReaction?: boolean) => boolean;
+ isDocumentActive?: () => boolean;
isSelected: (outsideReaction?: boolean) => boolean;
scaling?: () => number;
setHeight: (height: number) => void;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index bf9ca1de0..111509fdb 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -58,7 +58,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
value = eq ? value.substr(1) : value;
const dubEq = value.startsWith(":=") ? "computed" : value.startsWith(";=") ? "script" : false;
value = dubEq ? value.substr(2) : value;
- const options: ScriptOptions = { addReturn: true, params: { this: "Doc", _last_: "any" }, globals: true, editable: false };
+ const options: ScriptOptions = { addReturn: true, params: { this: "Doc", _last_: "any" }, editable: false };
if (dubEq) options.typecheck = false;
const script = CompileScript(value, options);
return !script.compiled ? undefined : { script, type: dubEq, onDelegate: eq };
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d55156057..d5056d934 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -262,6 +262,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
setPdfViewer={this.setPdfViewer}
addDocument={this.addDocument}
+ moveDocument={this.moveDocument}
+ removeDocument={this.removeDocument}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
startupLive={true}
ContentScaling={this.props.scaling}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 8c5f77550..f3fb6ff17 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -5,7 +5,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio
import { observer } from "mobx-react";
import { ColorState, SketchPicker } from "react-color";
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { Doc, DocListCast, DocListCastAsync } from "../../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, FieldResult } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { InkTool } from "../../../fields/InkField";
import { List } from "../../../fields/List";
@@ -29,6 +29,7 @@ import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
import Color = require("color");
+import { LightboxView } from "../LightboxView";
export enum PresMovement {
Zoom = "zoom",
@@ -246,11 +247,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
// }
}
- stopTempMedia = (targetDoc: Doc) => {
- if (targetDoc.type === DocumentType.AUDIO) {
+ stopTempMedia = (targetDocField: FieldResult) => {
+ const targetDoc = Cast(targetDocField, Doc, null);
+ if (targetDoc?.type === DocumentType.AUDIO) {
if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
targetDoc._audioStop = true;
- } else if (targetDoc.type === DocumentType.VID) {
+ } else if (targetDoc?.type === DocumentType.VID) {
if (this._mediaTimer && this._mediaTimer[1] === targetDoc) clearTimeout(this._mediaTimer[0]);
targetDoc._triggerVideoStop = true;
}
@@ -330,14 +332,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.rootDoc._itemIndex = index;
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
- if (from && from.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
- const mediaDocList = DocListCast(from.mediaStopTriggerList);
- mediaDocList.forEach((doc) => {
- this.stopTempMedia(Cast(doc.presentationTargetDoc, Doc, null));
- });
+ if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
+ DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
}
- if (from && from.mediaStop === "auto" && this.layoutDoc.presStatus !== PresStatus.Edit) {
- this.stopTempMedia(Cast(from.presentationTargetDoc, Doc, null));
+ if (from?.mediaStop === "auto" && this.layoutDoc.presStatus !== PresStatus.Edit) {
+ this.stopTempMedia(from.presentationTargetDoc);
}
// If next slide is audio / video 'Play automatically' then the next slide should be played
if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && (activeItem.mediaStart === "auto")) {
@@ -433,10 +432,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
};
// If openDocument is selected then it should open the document for the user
if (activeItem.openDocument) {
- openInTab(targetDoc);
+ LightboxView.SetLightboxDoc(targetDoc);
} else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
+ LightboxView.SetLightboxDoc(undefined);
await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right
} else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
+ LightboxView.SetLightboxDoc(undefined);
//awaiting jump so that new scale can be found, since jumping is async
await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right
}
@@ -574,6 +575,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
if (this._presTimer) clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
this.layoutDoc.presLoop = false;
+ this.childDocs.forEach(this.stopTempMedia);
}
}
@@ -633,10 +635,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
updateMinimize = () => {
const docView = DocumentManager.Instance.getDocumentView(this.layoutDoc);
if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+ console.log("case 1");
this.layoutDoc.presStatus = PresStatus.Edit;
Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
CollectionDockingView.AddSplit(this.rootDoc, "right");
} else if (this.layoutDoc.context && docView) {
+ console.log("case 2");
this.layoutDoc.presStatus = PresStatus.Edit;
clearTimeout(this._presTimer);
const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
@@ -647,15 +651,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
docView.props.removeDocument?.(this.layoutDoc);
Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
} else {
- this.layoutDoc.presStatus = PresStatus.Edit;
- clearTimeout(this._presTimer);
- const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
- this.rootDoc.y = pt[1] + 10;
- this.rootDoc._height = 35;
- this.rootDoc._width = 250;
- this.props.addDocTab?.(this.rootDoc, "close");
- Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
+ console.log("case 3");
+ // TODO glr: fix this case
}
}
@@ -1193,7 +1190,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
return (
- <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
+ <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
<div className="ribbon-box">
Movement
{isPresCollection || (isPresCollection && isPinWithView) ?
@@ -1248,7 +1245,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<div className="ribbon-doubleButton">
{isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideBefore ? "active" : ""}`} onClick={() => this.updateHideBefore(activeItem)}>Hide before</div></Tooltip>}
{isPresCollection ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfter ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>}
- <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? PresColor.LightBlue : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Open</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Open in lightbox view"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? PresColor.LightBlue : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Lightbox</div></Tooltip>
</div>
{(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) : <>
<div className="ribbon-doubleButton" >
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 8163b652c..c4f8d1143 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -11,20 +11,21 @@ import { makeInterface } from "../../../fields/Schema";
import { ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast } from "../../../fields/Types";
import { AudioField, VideoField } from "../../../fields/URLField";
+import { TraceMobx } from "../../../fields/util";
import { emptyFunction, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { Networking } from "../../Network";
+import { CaptureManager } from "../../util/CaptureManager";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { CollectionStackedTimeline } from "../collections/CollectionStackedTimeline";
import { ContextMenu } from "../ContextMenu";
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
import { FieldView, FieldViewProps } from './FieldView';
+import { FormattedTextBox } from "./formattedText/FormattedTextBox";
import "./ScreenshotBox.scss";
import { VideoBox } from "./VideoBox";
-import { TraceMobx } from "../../../fields/util";
-import { FormattedTextBox } from "./formattedText/FormattedTextBox";
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
}
@@ -35,7 +36,7 @@ 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 | null = null;
private _audioRec: any;
private _videoRec: any;
@observable _screenCapture = false;
@@ -53,7 +54,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) {
@@ -79,9 +80,17 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
@computed get 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 => {
+ this._videoRef = r;
+ setTimeout(() => {
+ if (this.rootDoc.mediaState === "pendingRecording" && this._videoRef) { // TODO glr: use mediaState
+ this.toggleRecording();
+ }
+ }, 1000);
+ }}
+ autoPlay={true}
+ style={{ width: "100%", height: "100%" }}
onCanPlay={this.videoLoad}
controls={true}
onClick={e => e.preventDefault()}>
@@ -102,8 +111,8 @@ 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);
@@ -129,6 +138,8 @@ 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);
}
});
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/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index ab178c60b..fc6f9ceab 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -2,20 +2,22 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import * as WebRequest from 'web-request';
-import { Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
import { InkTool } from "../../../fields/InkField";
import { List } from "../../../fields/List";
-import { makeInterface, listSpec } from "../../../fields/Schema";
+import { listSpec, makeInterface } from "../../../fields/Schema";
+import { ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { WebField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, getWordAtPoint, OmitKeys, returnOne, smoothScroll, Utils, setupMoveUpEvents } from "../../../Utils";
+import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { Scripting } from "../../util/Scripting";
import { SnappingManager } from "../../util/SnappingManager";
import { undoBatch } from "../../util/UndoManager";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
@@ -79,7 +81,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
runInAction(() => {
this._url = this.webField?.toString() || "";
- this._annotationKey = "annotations-" + this.urlHash(this._url);
+ this._annotationKey = "annotations-" + WebBox.urlHash(this._url);
+ // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created)
+ this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-annotations-"+urlHash(this["${this.fieldKey}"]?.url?.toString()))`);
});
this._disposers.selection = reaction(() => this.props.isSelected(),
@@ -289,7 +293,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (future.length) {
history.push(this._url);
this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = future.pop()!));
- this._annotationKey = "annotations-" + this.urlHash(this._url);
+ this._annotationKey = "annotations-" + WebBox.urlHash(this._url);
return true;
}
return false;
@@ -303,13 +307,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]);
else future.push(this._url);
this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!));
- this._annotationKey = "annotations-" + this.urlHash(this._url);
+ this._annotationKey = "annotations-" + WebBox.urlHash(this._url);
return true;
}
return false;
}
- urlHash = (s: string) => {
+ static urlHash = (s: string) => {
return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
}
@@ -331,7 +335,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
future && (future.length = 0);
}
this._url = newUrl;
- this._annotationKey = "annotations-" + this.urlHash(this._url);
+ this._annotationKey = "annotations-" + WebBox.urlHash(this._url);
this.dataDoc[this.fieldKey] = new WebField(new URL(newUrl));
} catch (e) {
console.log("WebBox URL error:" + this._url);
@@ -507,7 +511,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
PanelHeight={this.panelHeight}
dropAction={"alias"}
select={emptyFunction}
- isContentActive={this.isContentActive}
+ isContentActive={returnFalse}
ContentScaling={returnOne}
bringToFront={emptyFunction}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -555,4 +559,5 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</button>
</div>);
}
-} \ No newline at end of file
+}
+Scripting.addGlobal(function urlHash(url: string) { return WebBox.urlHash(url); }); \ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9482b632a..c2860af76 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -297,7 +297,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView.updateState(EditorState.fromJSON(this.config, json));
}
}
- if (window.getSelection()?.isCollapsed) AnchorMenu.Instance.fadeOut(true);
+ if (window.getSelection()?.isCollapsed && this.props.isSelected()) {
+ AnchorMenu.Instance.fadeOut(true);
+ }
}
}
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/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 4c181e49a..a2e7b0600 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -9,7 +9,7 @@ import { createSchema } from "../../../fields/Schema";
import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
import { PdfField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from "../../../Utils";
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils, returnFalse } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { Networking } from "../../Network";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -516,6 +516,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
}}>
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
isAnnotationOverlay={true}
+ isContentActive={returnFalse}
fieldKey={this.props.fieldKey + "-annotations"}
setPreviewCursor={this.setPreviewCursor}
PanelHeight={this.panelHeight}
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>;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 300dae0aa..9faba9486 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1324,7 +1324,7 @@ export namespace Doc {
}
-Scripting.addGlobal(function idToDoc(id: string) { return DocServer.GetCachedRefField(id); });
+Scripting.addGlobal(function idToDoc(id: string): any { return DocServer.GetCachedRefField(id); });
Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; });
Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); });
Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); });