aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deploy/index.html1
-rw-r--r--src/.DS_Storebin6148 -> 6148 bytes
-rw-r--r--src/client/documents/Documents.ts12
-rw-r--r--src/client/util/TooltipTextMenu.scss7
-rw-r--r--src/client/util/TooltipTextMenu.tsx2
-rw-r--r--src/client/views/.DS_Storebin6148 -> 8196 bytes
-rw-r--r--src/client/views/ContextMenu.scss77
-rw-r--r--src/client/views/ContextMenu.tsx16
-rw-r--r--src/client/views/DocumentDecorations.scss85
-rw-r--r--src/client/views/DocumentDecorations.tsx17
-rw-r--r--src/client/views/EditableView.scss6
-rw-r--r--src/client/views/EditableView.tsx3
-rw-r--r--src/client/views/InkingCanvas.scss131
-rw-r--r--src/client/views/InkingCanvas.tsx28
-rw-r--r--src/client/views/InkingControl.tsx66
-rw-r--r--src/client/views/InkingStroke.tsx2
-rw-r--r--src/client/views/Main.scss139
-rw-r--r--src/client/views/Main.tsx96
-rw-r--r--src/client/views/_global_variables.scss17
-rw-r--r--src/client/views/_nodeModuleOverrides.scss23
-rw-r--r--src/client/views/collections/CollectionFreeFormView.scss104
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx20
-rw-r--r--src/client/views/collections/CollectionPDFView.scss27
-rw-r--r--src/client/views/collections/CollectionPDFView.tsx26
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss383
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx32
-rw-r--r--src/client/views/collections/CollectionTreeView.scss32
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx25
-rw-r--r--src/client/views/collections/CollectionVideoView.scss40
-rw-r--r--src/client/views/collections/CollectionVideoView.tsx86
-rw-r--r--src/client/views/collections/CollectionView.tsx9
-rw-r--r--src/client/views/collections/MarqueeView.tsx49
-rw-r--r--src/client/views/collections/PreviewCursor.tsx8
-rw-r--r--src/client/views/nodes/AudioBox.tsx12
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx35
-rw-r--r--src/client/views/nodes/DocumentView.scss44
-rw-r--r--src/client/views/nodes/DocumentView.tsx22
-rw-r--r--src/client/views/nodes/FieldTextBox.scss14
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss64
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.scss25
-rw-r--r--src/client/views/nodes/ImageBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValueBox.scss42
-rw-r--r--src/client/views/nodes/LinkBox.scss42
-rw-r--r--src/client/views/nodes/LinkBox.tsx19
-rw-r--r--src/client/views/nodes/LinkEditor.scss22
-rw-r--r--src/client/views/nodes/LinkMenu.scss1
-rw-r--r--src/client/views/nodes/LinkMenu.tsx4
-rw-r--r--src/client/views/nodes/PDFBox.scss2
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.tsx18
-rw-r--r--src/fields/KeyStore.ts3
52 files changed, 1386 insertions, 558 deletions
diff --git a/deploy/index.html b/deploy/index.html
index e0892662a..130da1cb9 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -2,7 +2,6 @@
<head>
<title>Dash Web</title>
- <link href="https://fonts.googleapis.com/css?family=Fjalla+One|Hind+Siliguri:300" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/typescript/3.3.1/typescript.min.js"></script>
</head>
diff --git a/src/.DS_Store b/src/.DS_Store
index f20f36d63..90213270f 100644
--- a/src/.DS_Store
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f35d553b1..05bc743be 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -23,10 +23,13 @@ import { PDFField } from "../../fields/PDFField";
import { PDFBox } from "../views/nodes/PDFBox";
import { CollectionPDFView } from "../views/collections/CollectionPDFView";
import { RichTextField } from "../../fields/RichTextField";
+import { CollectionVideoView } from "../views/collections/CollectionVideoView";
+import { StrokeData, InkField } from "../../fields/InkField";
export interface DocumentOptions {
x?: number;
y?: number;
+ ink?: Map<string, StrokeData>;
width?: number;
height?: number;
nativeWidth?: number;
@@ -39,6 +42,7 @@ export interface DocumentOptions {
layout?: string;
layoutKeys?: Key[];
viewType?: number;
+ backgroundColor?: string;
}
export namespace Documents {
@@ -82,8 +86,10 @@ export namespace Documents {
if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); }
if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); }
if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); }
+ if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); }
if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); }
if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); }
+ if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); }
return doc;
}
function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document {
@@ -128,7 +134,7 @@ export namespace Documents {
function GetCollectionPrototype(): Document {
return collProto ? collProto :
collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("DataKey"),
- { panx: 0, pany: 0, scale: 1, layoutKeys: [KeyStore.Data] });
+ { panx: 0, pany: 0, scale: 1, width: 500, height: 500, layoutKeys: [KeyStore.Data] });
}
function GetKVPPrototype(): Document {
@@ -138,9 +144,9 @@ export namespace Documents {
}
function GetVideoPrototype(): Document {
if (!videoProto) {
- videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionView.LayoutString("AnnotationsKey"),
+ videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionVideoView.LayoutString("AnnotationsKey"),
{ x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations] });
- videoProto.SetNumber(KeyStore.CurFrame, 1);
+ videoProto.SetNumber(KeyStore.CurPage, 0);
videoProto.SetText(KeyStore.BackgroundLayout, VideoBox.LayoutString());
}
return videoProto;
diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index fa43f5326..ea580d104 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -1,8 +1,9 @@
+@import "../views/global_variables";
.tooltipMenu {
position: absolute;
z-index: 20;
- background: rgb(19, 18, 18);
+ background: $dark-color;
border: 1px solid silver;
border-radius: 4px;
padding: 2px 10px;
@@ -31,14 +32,14 @@
bottom: -4.5px;
border: 5px solid transparent;
border-bottom-width: 0;
- border-top-color: black;
+ border-top-color: $dark-color;
}
.menuicon {
display: inline-block;
border-right: 1px solid rgba(0, 0, 0, 0.2);
//color: rgb(19, 18, 18);
- color: white;
+ color: $light-color;
line-height: 1;
padding: 0px 2px;
margin: 1px;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 3b87fe9de..8cc653bf2 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -117,7 +117,7 @@ export class TooltipTextMenu {
let width = Math.abs(start.left - end.left) / 2;
let mid = Math.min(start.left, end.left) + width;
//THIS WIDTH IS 15 * NUMBER OF ICONS + 15
- this.tooltip.style.width = 120 + "px";
+ this.tooltip.style.width = 122 + "px";
this.tooltip.style.bottom = (box.bottom - start.top) + "px";
}
diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store
index 6bd614c8b..0964d5ff3 100644
--- a/src/client/views/.DS_Store
+++ b/src/client/views/.DS_Store
Binary files differ
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 41994ef79..f6830d9cd 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -1,42 +1,55 @@
+@import "global_variables";
.contextMenu-cont {
- position: absolute;
- display: flex;
- z-index: 1000;
- box-shadow: #AAAAAA .2vw .2vw .4vw;
- flex-direction: column;
+ position: absolute;
+ display: flex;
+ z-index: 1000;
+ box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw;
+ flex-direction: column;
+}
+
+.contextMenu-item:first-child {
+ background: $intermediate-color;
+ color: $light-color;
+}
+
+.contextMenu-item:first-child::placeholder {
+ color: $light-color;
+}
+
+.contextMenu-item:first-child:hover {
+ background: $intermediate-color;
+ color: $light-color;
}
.contextMenu-item {
- width: auto;
- height: auto;
- background: #F0F8FF;
- display: flex;
- justify-content: left;
- align-items: center;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- transition: all .1s;
- border-width: .11px;
- border-style: none;
- border-color: rgb(187, 186, 186);
- border-bottom-style: solid;
- padding: 10px;
- white-space: nowrap;
- // font-size: 1.5vw;
- font-size: 12px;
+ width: auto;
+ height: auto;
+ background: $light-color-secondary;
+ display: flex;
+ justify-content: left;
+ align-items: center;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ transition: all 0.1s;
+ border-width: 0.11px;
+ border-style: none;
+ border-color: $intermediate-color;
+ border-bottom-style: solid;
+ padding: 10px;
+ white-space: nowrap;
+ font-size: 13px;
}
.contextMenu-item:hover {
- transition: all .1s;
- background: #B0E0E6;
+ transition: all 0.1s;
+ background: $lighter-alt-accent;
}
.contextMenu-description {
- // font-size: 1.5vw;
- text-align: left;
- // width: 8vw;
-} \ No newline at end of file
+ text-align: left;
+ width: 8vw;
+}
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 12352c667..9109b56bb 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -13,6 +13,8 @@ export class ContextMenu extends React.Component {
@observable private _pageY: number = 0;
@observable private _display: string = "none";
@observable private _searchString: string = "";
+ // afaik displaymenu can be called before all the items are added to the menu, so can't determine in displayMenu what the height of the menu will be
+ @observable private _yRelativeToTop: boolean = true;
private ref: React.RefObject<HTMLDivElement>;
@@ -59,8 +61,13 @@ export class ContextMenu extends React.Component {
intersects = (x: number, y: number): boolean => {
if (this.ref.current && this._display !== "none") {
- if (x >= this._pageX && x <= this._pageX + this.ref.current.getBoundingClientRect().width) {
- if (y >= this._pageY && y <= this._pageY + this.ref.current.getBoundingClientRect().height) {
+ let menuSize = { width: this.ref.current.getBoundingClientRect().width, height: this.ref.current.getBoundingClientRect().height };
+
+ let upperLeft = { x: this._pageX, y: this._yRelativeToTop ? this._pageY : window.innerHeight - (this._pageY + menuSize.height) };
+ let bottomRight = { x: this._pageX + menuSize.width, y: this._yRelativeToTop ? this._pageY + menuSize.height : window.innerHeight - this._pageY };
+
+ if (x >= upperLeft.x && x <= bottomRight.x) {
+ if (y >= upperLeft.y && y <= bottomRight.y) {
return true;
}
}
@@ -69,9 +76,12 @@ export class ContextMenu extends React.Component {
}
render() {
+ let style = this._yRelativeToTop ? { left: this._pageX, top: this._pageY, display: this._display } :
+ { left: this._pageX, bottom: this._pageY, display: this._display };
+
return (
- <div className="contextMenu-cont" style={{ left: this._pageX, top: this._pageY, display: this._display }} ref={this.ref}>
+ <div className="contextMenu-cont" style={style} ref={this.ref}>
<input className="contextMenu-item" type="text" placeholder="Search . . ." value={this._searchString} onChange={this.onChange}></input>
{this._items.filter(prop => {
return prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1;
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index fb9091dfc..11595aa01 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -1,17 +1,18 @@
+@import "global_variables";
#documentDecorations-container {
position: absolute;
display: grid;
z-index: 1000;
- grid-template-rows: 20px 1fr 20px 0px;
- grid-template-columns: 20px 1fr 20px;
+ grid-template-rows: 8px 1fr 8px 30px;
+ grid-template-columns: 8px 1fr 8px;
pointer-events: none;
#documentDecorations-centerCont {
background: none;
}
.documentDecorations-resizer {
pointer-events: auto;
- background: lightblue;
- opacity: 0.4;
+ background: $alt-accent;
+ opacity: 0.8;
}
#documentDecorations-topLeftResizer,
#documentDecorations-bottomRightResizer {
@@ -29,23 +30,89 @@
#documentDecorations-rightResizer {
cursor: ew-resize;
}
-
}
+
+// position: absolute;
+// display: grid;
+// z-index: 1000;
+// grid-template-rows: 20px 1fr 20px 0px;
+// grid-template-columns: 20px 1fr 20px;
+// pointer-events: none;
+// #documentDecorations-centerCont {
+// background: none;
+// }
+// .documentDecorations-resizer {
+// pointer-events: auto;
+// background: lightblue;
+// opacity: 0.4;
+// }
+// #documentDecorations-topLeftResizer,
+// #documentDecorations-bottomRightResizer {
+// cursor: nwse-resize;
+// }
+// #documentDecorations-topRightResizer,
+// #documentDecorations-bottomLeftResizer {
+// cursor: nesw-resize;
+// }
+// #documentDecorations-topResizer,
+// #documentDecorations-bottomResizer {
+// cursor: ns-resize;
+// }
+// #documentDecorations-leftResizer,
+// #documentDecorations-rightResizer {
+// cursor: ew-resize;
+// }
+// }
+.linkFlyout {
+ grid-column: 1/4
+}
+
+.linkButton-empty:hover {
+ background: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
+}
+
+.linkButton-nonempty:hover {
+ background: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
+}
+
.linkButton-empty {
height: 20px;
width: 20px;
margin-top: 10px;
border-radius: 50%;
- opacity: 0.6;
+ opacity: 0.9;
pointer-events: auto;
- background-color: #2B6091;
+ background-color: $dark-color;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
+
.linkButton-nonempty {
height: 20px;
width: 20px;
margin-top: 10px;
border-radius: 50%;
- opacity: 0.6;
+ opacity: 0.9;
pointer-events: auto;
- background-color: rgb(35, 165, 42);
+ background-color: $dark-color;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
} \ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index dc62f97cf..3bdb7d5b3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -18,6 +18,8 @@ export class DocumentDecorations extends React.Component {
static Instance: DocumentDecorations
private _resizer = ""
private _isPointerDown = false;
+
+ private _resizeBorderWidth = 16;
private _linkButton = React.createRef<HTMLDivElement>();
@observable private _hidden = false;
@@ -206,21 +208,24 @@ export class DocumentDecorations extends React.Component {
let linkButton = null;
if (SelectionManager.SelectedDocuments().length > 0) {
let selFirst = SelectionManager.SelectedDocuments()[0];
+ let linkToSize = selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length;
+ let linkFromSize = selFirst.props.Document.GetData(KeyStore.LinkedFromDocs, ListField, []).length;
+ let linkCount = linkToSize + linkFromSize;
linkButton = (<Flyout
anchorPoint={anchorPoints.RIGHT_TOP}
content={
<LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent}>
</LinkMenu>
}>
- <div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} ref={this._linkButton} />
+ <div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} ref={this._linkButton}>{linkCount}</div>
</Flyout>);
}
return (
<div id="documentDecorations-container" style={{
- width: (bounds.r - bounds.x + 40) + "px",
- height: (bounds.b - bounds.y + 40) + "px",
- left: bounds.x - 20,
- top: bounds.y - 20,
+ width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
+ height: (bounds.b - bounds.y + this._resizeBorderWidth + 30) + "px",
+ left: bounds.x - this._resizeBorderWidth / 2,
+ top: bounds.y - this._resizeBorderWidth / 2,
}}>
<div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
@@ -232,7 +237,7 @@ export class DocumentDecorations extends React.Component {
<div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- {linkButton}
+ <div title="View Links" className="linkFlyout">{linkButton}</div>
</div >
)
diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
new file mode 100644
index 000000000..be3c5069a
--- /dev/null
+++ b/src/client/views/EditableView.scss
@@ -0,0 +1,6 @@
+.editableView-container-editing {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ hyphens: auto;
+ max-width: 300px;
+} \ No newline at end of file
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 84b1b91c3..3b54c0dbb 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -1,6 +1,7 @@
import React = require('react')
import { observer } from 'mobx-react';
import { observable, action } from 'mobx';
+import "./EditableView.scss"
export interface EditableProps {
/**
@@ -49,7 +50,7 @@ export class EditableView extends React.Component<EditableProps> {
style={{ display: "inline" }}></input>
} else {
return (
- <div className="editableView-container-editing" style={{ display: "inline", height: "100%", maxHeight: `${this.props.height}` }}
+ <div className="editableView-container-editing" style={{ display: "inline", height: "auto", maxHeight: `${this.props.height}` }}
onClick={action(() => this.editing = true)}>
{this.props.contents}
</div>
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index f654b194b..e79b146b9 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,8 +1,10 @@
+@import "global_variables";
.inking-canvas {
- position: fixed;
+ position: absolute;
top: -50000px;
left: -50000px; // z-index: 99; //overlays ink on top of everything
svg {
+ position:absolute;
width: 100000px;
height: 100000px;
.highlight {
@@ -13,20 +15,135 @@
.inking-control {
position: absolute;
- right: 0;
- bottom: 75px;
- text-align: right;
+ left: 70px;
+ bottom: 70px;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ label,
+ input,
+ option {
+ font-size: 12px;
+ }
+ input[type="range"] {
+ -webkit-appearance: none;
+ background-color: transparent;
+ vertical-align: middle;
+ margin-top: 8px;
+ &:focus {
+ outline: none;
+ }
+ &::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 3px;
+ border-radius: 1.5px;
+ cursor: pointer;
+ background: $intermediate-color;
+ }
+ &::-webkit-slider-thumb {
+ height: 12px;
+ width: 12px;
+ border: 1px solid $intermediate-color;
+ border-radius: 6px;
+ background: $light-color;
+ cursor: pointer;
+ -webkit-appearance: none;
+ margin-top: -4px;
+ }
+ &::-moz-range-track {
+ width: 100%;
+ height: 3px;
+ border-radius: 1.5px;
+ cursor: pointer;
+ background: $light-color;
+ }
+ &::-moz-range-thumb {
+ height: 12px;
+ width: 12px;
+ border: 1px solid $intermediate-color;
+ border-radius: 6px;
+ background: $light-color;
+ cursor: pointer;
+ -webkit-appearance: none;
+ margin-top: -4px;
+ }
+ }
+ input[type="text"] {
+ border: none;
+ padding: 0 0px;
+ background: transparent;
+ color: $dark-color;
+ font-size: 12px;
+ margin-top: 4px;
+ }
.ink-panel {
- margin-top: 12px;
+ margin: 6px 12px 6px 0;
+ height: 30px;
+ vertical-align: middle;
+ line-height: 36px;
+ padding: 0 10px;
+ color: $intermediate-color;
&:first {
margin-top: 0;
}
}
+ .ink-tools {
+ display: flex;
+ background-color: transparent;
+ border-radius: 0;
+ padding: 0;
+ button {
+ height: 36px;
+ padding: 0px;
+ padding-bottom: 3px;
+ margin-left: 10px;
+ background-color: transparent;
+ color: $intermediate-color;
+ }
+ button:hover {
+ transform: scale(1.15);
+ }
+ }
.ink-size {
display: flex;
justify-content: space-between;
- input {
- width: 85%;
+ input[type="text"] {
+ width: 42px;
+ }
+ >* {
+ margin-right: 6px;
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+ .ink-color {
+ display: flex;
+ position: relative;
+ padding-right: 0;
+ label {
+ margin-right: 6px;
+ }
+ .ink-color-display {
+ border-radius: 11px;
+ width: 22px;
+ height: 22px;
+ margin-top: 6px;
+ cursor: pointer;
+ text-align: center; // span {
+ // color: $light-color;
+ // font-size: 8px;
+ // user-select: none;
+ // }
+ }
+ .ink-color-picker {
+ background-color: $light-color;
+ border-radius: 5px;
+ padding: 12px;
+ position: absolute;
+ bottom: 36px;
+ left: -3px;
+ box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
}
}
} \ No newline at end of file
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 0d87c1239..84c47f616 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -1,4 +1,5 @@
import { observer } from "mobx-react";
+import { observable } from "mobx";
import { action, computed } from "mobx";
import { InkingControl } from "./InkingControl";
import React = require("react");
@@ -6,14 +7,10 @@ import { Transform } from "../util/Transform";
import { Document } from "../../fields/Document";
import { KeyStore } from "../../fields/KeyStore";
import { InkField, InkTool, StrokeData, StrokeMap } from "../../fields/InkField";
-import { JsxArgs } from "./nodes/DocumentView";
import { InkingStroke } from "./InkingStroke";
import "./InkingCanvas.scss"
-import { CollectionDockingView } from "./collections/CollectionDockingView";
import { Utils } from "../../Utils";
import { FieldWaiting } from "../../fields/Field";
-import { getMapLikeKeys } from "mobx/lib/internal";
-
interface InkCanvasProps {
getScreenTransform: () => Transform;
@@ -22,7 +19,16 @@ interface InkCanvasProps {
@observer
export class InkingCanvas extends React.Component<InkCanvasProps> {
-
+ static InkOffset: number = 50000;
+ public static IntersectStrokeRect(stroke: StrokeData, selRect: { left: number, top: number, width: number, height: number }): boolean {
+ let inside = false;
+ stroke.pathData.map(val => {
+ if (selRect.left < val.x - InkingCanvas.InkOffset && selRect.left + selRect.width > val.x - InkingCanvas.InkOffset &&
+ selRect.top < val.y - InkingCanvas.InkOffset && selRect.top + selRect.height > val.y - InkingCanvas.InkOffset)
+ inside = true;
+ });
+ return inside
+ }
private _isDrawing: boolean = false;
private _idGenerator: string = "";
@@ -51,7 +57,6 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
document.removeEventListener("mouseup", this.handleMouseUp);
}
-
@action
handleMouseDown = (e: React.PointerEvent): void => {
if (e.button != 0 ||
@@ -62,7 +67,6 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
if (InkingControl.Instance.selectedTool === InkTool.Eraser) {
return
}
- e.stopPropagation()
const point = this.relativeCoordinatesForEvent(e);
// start the new line, saves a uuid to represent the field of the stroke
@@ -74,7 +78,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
color: InkingControl.Instance.selectedColor,
width: InkingControl.Instance.selectedWidth,
tool: InkingControl.Instance.selectedTool,
- page: this.props.Document.GetNumber(KeyStore.CurPage, 0)
+ page: this.props.Document.GetNumber(KeyStore.CurPage, -1)
});
this.inkData = data;
this._isDrawing = true;
@@ -110,8 +114,8 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
relativeCoordinatesForEvent = (e: React.MouseEvent): { x: number, y: number } => {
let [x, y] = this.props.getScreenTransform().transformPoint(e.clientX, e.clientY);
- x += 50000
- y += 50000
+ x += InkingCanvas.InkOffset;
+ y += InkingCanvas.InkOffset;
return { x, y };
}
@@ -145,11 +149,11 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
// parse data from server
let paths: Array<JSX.Element> = []
- let curPage = this.props.Document.GetNumber(KeyStore.CurPage, 0)
+ let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1)
Array.from(lines).map(item => {
let id = item[0];
let strokeData = item[1];
- if (strokeData.page == 0 || strokeData.page == curPage)
+ if (strokeData.page == -1 || strokeData.page == curPage)
paths.push(<InkingStroke key={id} id={id}
line={strokeData.pathData}
color={strokeData.color}
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 955831fb6..fb75ef2a5 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -1,16 +1,25 @@
import { observable, action, computed } from "mobx";
-import { CirclePicker, ColorResult } from 'react-color';
+
+import { CirclePicker, ColorResult } from 'react-color'
import React = require("react");
import "./InkingCanvas.scss"
import { InkTool } from "../../fields/InkField";
import { observer } from "mobx-react";
+import "./InkingCanvas.scss"
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
+
+library.add(faPen, faHighlighter, faEraser, faBan);
@observer
export class InkingControl extends React.Component {
static Instance: InkingControl = new InkingControl({});
@observable private _selectedTool: InkTool = InkTool.None;
- @observable private _selectedColor: string = "#f44336";
+ @observable private _selectedColor: string = "rgb(244, 67, 54)";
@observable private _selectedWidth: string = "25";
+ @observable private _open: boolean = false;
+ @observable private _colorPickerDisplay: boolean = false;
constructor(props: Readonly<{}>) {
super(props);
@@ -49,29 +58,50 @@ export class InkingControl extends React.Component {
selected = (tool: InkTool) => {
if (this._selectedTool === tool) {
- return { backgroundColor: "black", color: "white" }
+ return { color: "#61aaa3" }
}
return {}
}
+ @action
+ toggleDisplay = () => {
+ this._open = !this._open;
+ }
+
+ @action
+ toggleColorPicker = () => {
+ this._colorPickerDisplay = !this._colorPickerDisplay;
+ }
+
render() {
return (
- <div className="inking-control">
- <div className="ink-tools ink-panel">
- <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}>Pen</button>
- <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}>Highlighter</button>
- <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}>Eraser</button>
- <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}> None</button>
- </div>
- <div className="ink-size ink-panel">
- <label htmlFor="stroke-width">Size</label>
- <input type="range" min="1" max="100" defaultValue="25" name="stroke-width"
+ <ul className="inking-control" style={this._open ? { display: "flex" } : { display: "none" }}>
+ <li className="ink-tools ink-panel">
+ <div className="ink-tool-buttons">
+ <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="lg" title="Pen" /></button>
+ <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="lg" title="Highlighter" /></button>
+ <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="lg" title="Eraser" /></button>
+ <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}><FontAwesomeIcon icon="ban" size="lg" title="Pointer" /></button>
+ </div>
+ </li>
+ <li className="ink-color ink-panel">
+ <label>COLOR: </label>
+ <div className="ink-color-display" style={{ backgroundColor: this._selectedColor }}
+ onClick={() => this.toggleColorPicker()}>
+ {/* {this._colorPickerDisplay ? <span>&#9660;</span> : <span>&#9650;</span>} */}
+ </div>
+ <div className="ink-color-picker" style={this._colorPickerDisplay ? { display: "block" } : { display: "none" }}>
+ <CirclePicker onChange={this.switchColor} circleSize={22} width={"220"} />
+ </div>
+ </li>
+ <li className="ink-size ink-panel">
+ <label htmlFor="stroke-width">SIZE: </label>
+ <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
+ <input type="range" min="1" max="100" value={this._selectedWidth} name="stroke-width"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
- </div>
- <div className="ink-color ink-panel">
- <CirclePicker onChange={this.switchColor} />
- </div>
- </div>
+ </li>
+ </ul >
)
}
} \ No newline at end of file
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index d724421d3..87b5c43d8 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -21,8 +21,6 @@ export class InkingStroke extends React.Component<StrokeProps> {
@observable private _strokeColor: string = this.props.color;
@observable private _strokeWidth: string = this.props.width;
- private _canvasColor: string = "#cdcdcd";
-
deleteStroke = (e: React.MouseEvent): void => {
if (InkingControl.Instance.selectedTool === InkTool.Eraser && e.buttons === 1) {
this.props.deleteCallback(this.props.id);
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 2b1c77b74..bb42db202 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -1,22 +1,35 @@
+@import "global_variables";
+@import "nodeModuleOverrides";
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
- font-family: 'Hind Siliguri', sans-serif;
+ font-family: $sans-serif;
margin: 0;
}
+#dash-title {
+ position: absolute;
+ right: 46.5%;
+ letter-spacing: 3px;
+ top: 9px;
+ font-size: 12px;
+ color: $alt-accent;
+ z-index: 9999;
+}
+
h1 {
font-size: 50px;
position: fixed;
top: 30px;
left: 50%;
transform: translateX(-50%);
- color: black;
+ color: $dark-color;
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
z-index: 9999;
- font-family: 'Fjalla One', sans-serif;
+ font-family: $sans-serif;
+ font-weight: 700;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
@@ -33,23 +46,131 @@ p {
margin: 0px;
padding: 0px;
}
+
::-webkit-scrollbar {
-webkit-appearance: none;
- height:5px;
- width:5px;
+ height: 5px;
+ width: 5px;
}
+
::-webkit-scrollbar-thumb {
border-radius: 2px;
- background-color: rgba(0,0,0,.5);
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+// button stuff
+button {
+ background: $dark-color;
+ outline: none;
+ border: 0px;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ padding: 10px;
+ transition: transform 0.2s;
+}
+
+button:hover {
+ background: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
}
-.main-buttonDiv {
+.clear-db-button {
position: absolute;
- width: 150px;
- left: 0px;
+ right: 45%;
+ bottom: 3%;
+ font-size: 50%;
+}
+
+.round-button {
+ width: 36px;
+ height: 36px;
+ border-radius: 18px;
+ font-size: 15px;
+}
+
+.round-button:hover {
+ transform: scale(1.15);
+}
+
+.add-button {
+ position: relative;
+ margin-right: 10px;
}
+
.main-undoButtons {
position: absolute;
width: 150px;
right: 0px;
}
+
+//toolbar stuff
+#toolbar {
+ position: absolute;
+ bottom: 62px;
+ left: 24px;
+ .toolbar-button {
+ display: block;
+ margin-bottom: 10px;
+ }
+}
+
+// add nodes menu. Note that the + button is actually an input label, not an actual button.
+#add-nodes-menu {
+ position: absolute;
+ bottom: 24px;
+ left: 24px;
+ label {
+ background: $dark-color;
+ color: $light-color;
+ display: inline-block;
+ border-radius: 18px;
+ font-size: 25px;
+ width: 36px;
+ height: 36px;
+ margin-right: 10px;
+ cursor: pointer;
+ transition: transform 0.2s;
+ }
+ label p {
+ padding-left: 10.5px;
+ padding-top: 3px;
+ }
+ label:hover {
+ background: $main-accent;
+ transform: scale(1.15);
+ }
+ input {
+ display: none;
+ }
+ input:not(:checked)~#add-options-content {
+ display: none;
+ }
+ input:checked~label {
+ transform: rotate(45deg);
+ transition: transform 0.5s;
+ cursor: pointer;
+ }
+}
+
+#add-options-content {
+ display: table;
+ opacity: 1;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ float: right;
+ bottom: 0.3em;
+ margin-bottom: -1.68em;
+}
+
+ul#add-options-list {
+ list-style: none;
+ padding: 0;
+ li {
+ display: inline-block;
+ padding: 0;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 95bf9cad0..3a68b98ce 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -18,6 +18,19 @@ import { DocumentDecorations } from './DocumentDecorations';
import { DocumentView } from './nodes/DocumentView';
import "./Main.scss";
import { InkingControl } from './InkingControl';
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faFont } from '@fortawesome/free-solid-svg-icons';
+import { faImage } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf } from '@fortawesome/free-solid-svg-icons';
+import { faObjectGroup } from '@fortawesome/free-solid-svg-icons';
+import { faTable } from '@fortawesome/free-solid-svg-icons';
+import { faGlobeAsia } from '@fortawesome/free-solid-svg-icons';
+import { faUndoAlt } from '@fortawesome/free-solid-svg-icons';
+import { faRedoAlt } from '@fortawesome/free-solid-svg-icons';
+import { faPenNib } from '@fortawesome/free-solid-svg-icons';
+import { faFilm } from '@fortawesome/free-solid-svg-icons';
+import { faMusic } from '@fortawesome/free-solid-svg-icons';
configure({ enforceActions: "observed" }); // causes errors to be generated when modifying an observable outside of an action
@@ -29,10 +42,22 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
}
}), true)
-
const mainDocId = "mainDoc";
let mainContainer: Document;
let mainfreeform: Document;
+
+library.add(faFont);
+library.add(faImage);
+library.add(faFilePdf);
+library.add(faObjectGroup);
+library.add(faTable);
+library.add(faGlobeAsia);
+library.add(faUndoAlt);
+library.add(faRedoAlt);
+library.add(faPenNib);
+library.add(faFilm);
+library.add(faMusic);
+
Documents.initProtos(mainDocId, (res?: Document) => {
if (res instanceof Document) {
mainContainer = res;
@@ -80,6 +105,8 @@ Documents.initProtos(mainDocId, (res?: Document) => {
ReactDOM.render((
<div style={{ position: "absolute", width: "100%", height: "100%" }}>
+ {/* <div id="dash-title">— DASH —</div> */}
+
<DocumentView Document={mainContainer}
AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity}
ContentScaling={() => 1}
@@ -91,27 +118,52 @@ Documents.initProtos(mainDocId, (res?: Document) => {
ContainingCollectionView={undefined} />
<DocumentDecorations />
<ContextMenu />
- <div className="main-buttonDiv" style={{ bottom: '0px' }} ref={imgRef} >
- <button onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>Add Image</button></div>
- <div className="main-buttonDiv" style={{ bottom: '25px' }} ref={webRef} >
- <button onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>Add Web</button></div>
- <div className="main-buttonDiv" style={{ bottom: '50px' }} ref={textRef}>
- <button onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>Add Text</button></div>
- <div className="main-buttonDiv" style={{ bottom: '75px' }} ref={colRef}>
- <button onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>Add Collection</button></div>
- <div className="main-buttonDiv" style={{ bottom: '100px' }} ref={schemaRef}>
- <button onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>Add Schema</button></div>
- <div className="main-buttonDiv" style={{ bottom: '125px' }} >
- <button onClick={clearDatabase}>Clear Database</button></div>
- <div className="main-buttonDiv" style={{ bottom: '175px' }} ref={videoRef}>
- <button onPointerDown={setupDrag(videoRef, addVideoNode)} onClick={addClick(addVideoNode)}>Add Videoooo</button></div>
- <div className="main-buttonDiv" style={{ bottom: '200px' }} ref={audioRef}>
- <button onPointerDown={setupDrag(audioRef, addAudioNode)} onClick={addClick(addAudioNode)}>Add Audio</button></div>
- <div className="main-buttonDiv" style={{ bottom: '150px' }} ref={pdfRef}>
- <button onPointerDown={setupDrag(pdfRef, addPDFNode)} onClick={addClick(addPDFNode)}>Add PDF</button></div>
- <button className="main-undoButtons" style={{ bottom: '25px' }} onClick={() => UndoManager.Undo()}>Undo</button>
- <button className="main-undoButtons" style={{ bottom: '0px' }} onClick={() => UndoManager.Redo()}>Redo</button>
+ <button className="clear-db-button" onClick={clearDatabase}>Clear Database</button>
+
+ {/* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */}
+ < div id="toolbar" >
+ <button className="toolbar-button round-button" title="Undo" onClick={() => UndoManager.Undo()}><FontAwesomeIcon icon="undo-alt" size="sm" /></button>
+ <button className="toolbar-button round-button" title="Redo" onClick={() => UndoManager.Redo()}><FontAwesomeIcon icon="redo-alt" size="sm" /></button>
+ <button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /></button>
+ </div >
+
+ {/* for the expandable add nodes menu. Not included with the above because once it expands it expands the whole div with it, making canvas interactions limited. */}
+ < div id="add-nodes-menu" >
+ <input type="checkbox" id="add-menu-toggle" />
+ <label htmlFor="add-menu-toggle" title="Add Node"><p>+</p></label>
+
+ <div id="add-options-content">
+ <ul id="add-options-list">
+ <li><div ref={textRef}><button className="round-button add-button" title="Add Textbox" onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>
+ <FontAwesomeIcon icon="font" size="sm" />
+ </button></div></li>
+ <li><div ref={imgRef}><button className="round-button add-button" title="Add Image" onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>
+ <FontAwesomeIcon icon="image" size="sm" />
+ </button></div></li>
+ <li><div ref={pdfRef}><button className="round-button add-button" title="Add PDF" onPointerDown={setupDrag(pdfRef, addPDFNode)} onClick={addClick(addPDFNode)}>
+ <FontAwesomeIcon icon="file-pdf" size="sm" />
+ </button></div></li>
+ <li><div ref={videoRef}><button className="round-button add-button" title="Add Video" onPointerDown={setupDrag(videoRef, addVideoNode)} onClick={addClick(addVideoNode)}>
+ <FontAwesomeIcon icon="film" size="sm" />
+ </button></div></li>
+ <li><div ref={audioRef}><button className="round-button add-button" title="Add Audio" onPointerDown={setupDrag(audioRef, addAudioNode)} onClick={addClick(addAudioNode)}>
+ <FontAwesomeIcon icon="music" size="sm" />
+ </button></div></li>
+ <li><div ref={webRef}><button className="round-button add-button" title="Add Web Clipping" onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>
+ <FontAwesomeIcon icon="globe-asia" size="sm" />
+ </button></div></li>
+ <li><div ref={colRef}><button className="round-button add-button" title="Add Collection" onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>
+ <FontAwesomeIcon icon="object-group" size="sm" />
+ </button></div></li>
+ <li><div ref={schemaRef}><button className="round-button add-button" title="Add Schema" onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>
+ <FontAwesomeIcon icon="table" size="sm" />
+ </button></div></li>
+ </ul>
+ </div>
+
+ </div >
+
<InkingControl />
- </div>),
+ </div >),
document.getElementById('root'));
})
diff --git a/src/client/views/_global_variables.scss b/src/client/views/_global_variables.scss
new file mode 100644
index 000000000..44a819b79
--- /dev/null
+++ b/src/client/views/_global_variables.scss
@@ -0,0 +1,17 @@
+@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Crimson+Text:400,400i,700");
+// colors
+$light-color: #fcfbf7;
+$light-color-secondary: rgb(241, 239, 235);
+$main-accent: #61aaa3;
+// $alt-accent: #cdd5ec;
+// $alt-accent: #cdeceb;
+$alt-accent: #59dff7;
+$lighter-alt-accent: rgb(207, 220, 240);
+$intermediate-color: #9c9396;
+$dark-color: #121721;
+// fonts
+$sans-serif: "Noto Sans", sans-serif;
+// $sans-serif: "Roboto Slab", sans-serif;
+$serif: "Crimson Text", serif;
+// misc values
+$border-radius: 0.3em;
diff --git a/src/client/views/_nodeModuleOverrides.scss b/src/client/views/_nodeModuleOverrides.scss
new file mode 100644
index 000000000..6f97e60f8
--- /dev/null
+++ b/src/client/views/_nodeModuleOverrides.scss
@@ -0,0 +1,23 @@
+// this file is for overriding all the css from installed node modules
+
+// goldenlayout stuff
+div .lm_header {
+ background: $dark-color;
+ min-height: 2em;
+}
+
+.lm_tab {
+ margin-top: 0.6em !important;
+ padding-top: 0.5em !important;
+ min-height: 1.35em;
+ padding-bottom: 0px;
+ border-radius: 5px;
+ font-family: $sans-serif !important;
+}
+
+.lm_header .lm_controls {
+ right: 1em !important;
+}
+
+// @TODO the ril__navgiation buttons in the img gallery are a lil messed up but I can't figure out
+// why. Low priority for now but it's bugging me. --Julie
diff --git a/src/client/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss
index d472cc5c4..9c7a03b52 100644
--- a/src/client/views/collections/CollectionFreeFormView.scss
+++ b/src/client/views/collections/CollectionFreeFormView.scss
@@ -1,29 +1,56 @@
+@import "../global_variables";
+
.collectionfreeformview-container {
+ .collectionfreeformview > .jsx-parser {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ }
- .collectionfreeformview > .jsx-parser{
- position:absolute;
- height: 100%;
- width: 100%;
- }
-
- border-style: solid;
- box-sizing: border-box;
- position: relative;
+ //nested freeform views
+ .collectionfreeformview-container {
+ // background-image: linear-gradient(to right, $light-color-secondary 1px, transparent 1px),
+ // linear-gradient(to bottom, $light-color-secondary 1px, transparent 1px);
+ // background-size: 30px 30px;
+ }
+
+ border: 0px solid $light-color-secondary;
+ border-radius: $border-radius;
+ box-sizing: border-box;
+ position: relative;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
+ .collectionfreeformview {
+ position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
- overflow: hidden;
- .collectionfreeformview {
- position: absolute;
- top: 0;
- left: 0;
- width:100%;
- height: 100%;
- }
+ }
}
.collectionfreeformview-overlay {
+ .collectionfreeformview > .jsx-parser {
+ position: absolute;
+ height: 100%;
+ }
+ .formattedTextBox-cont {
+ background: $light-color-secondary;
+ }
+ position:absolute;
+ border: 0px solid transparent;
+ border-radius: $border-radius;
+ overflow: hidden;
+ box-sizing: border-box;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ .collectionfreeformview {
.collectionfreeformview > .jsx-parser{
position:absolute;
height: 100%;
@@ -32,26 +59,39 @@
background:yellow;
}
- border-style: solid;
- box-sizing: border-box;
+ // overflow: hidden;
+ // border-style: solid;
+ // box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
- overflow: hidden;
- .collectionfreeformview {
- position: absolute;
- top: 0;
- left: 0;
- width:100%;
- height: 100%;
- }
+ }
}
+// selection border...?
.border {
- border-style: solid;
- box-sizing: border-box;
- width: 100%;
- height: 100%;
-} \ No newline at end of file
+ border-style: solid;
+ box-sizing: border-box;
+ width: 98%;
+ height: 98%;
+ border-radius: $border-radius;
+}
+
+//this is an animation for the blinking cursor!
+@keyframes blink {
+ 0% {
+ opacity: 0;
+ }
+ 49% {
+ opacity: 0;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+#prevCursor {
+ animation: blink 1s infinite;
+}
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 3d5326552..5c0eab392 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -52,13 +52,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
public getActiveDocuments = () => {
- var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
+ var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
let active: Document[] = [];
if (lvalue && lvalue != FieldWaiting) {
lvalue.Data.map(doc => {
- var page = doc.GetNumber(KeyStore.Page, 0);
- if (page == curPage || page == 0) {
+ var page = doc.GetNumber(KeyStore.Page, -1);
+ if (page == curPage || page == -1) {
active.push(doc);
}
})
@@ -126,7 +126,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
onPointerUp = (e: PointerEvent): void => {
e.stopPropagation();
- if (!this.MarqueeVisible && Math.abs(this.DownX - e.clientX) < 3 && Math.abs(this.DownY - e.clientY) < 3) {
+ if (Math.abs(this.DownX - e.clientX) < 4 && Math.abs(this.DownY - e.clientY) < 4) {
//show preview text cursor on tap
this.PreviewCursorVisible = true;
//select is not already selected
@@ -140,9 +140,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
onPointerMove = (e: PointerEvent): void => {
if (!e.cancelBubble && this.props.active()) {
- if (e.buttons != 2 && !e.altKey && !e.metaKey && !this.MarqueeVisible) {
+ if (e.buttons == 1 && !e.altKey && !e.metaKey) {
this.MarqueeVisible = true;
- this.PreviewCursorVisible = false;
}
if (this.MarqueeVisible) {
e.stopPropagation();
@@ -152,7 +151,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- this.PreviewCursorVisible = false;
this.SetPan(x - dx, y - dy);
this._lastX = e.pageX;
this._lastY = e.pageY;
@@ -272,7 +270,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
@computed
get views() {
- var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
+ var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
if (lvalue && lvalue != FieldWaiting) {
return lvalue.Data.map(doc => {
@@ -343,10 +341,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
ref={this._canvasRef}>
{this.backgroundView}
<InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
- <PreviewCursor container={this} addLiveTextDocuemnt={this.addLiveTextBox} getTransform={this.getTransform} />
+ <PreviewCursor container={this} addLiveTextDocument={this.addLiveTextBox} getTransform={this.getTransform} />
{this.views}
</div>
- <MarqueeView container={this} activeDocuemnts={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} getMarqueeTransform={this.getMarqueeTransform} getTransform={this.getTransform} />
+ <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
+ addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
+ getMarqueeTransform={this.getMarqueeTransform} getTransform={this.getTransform} />
{this.overlayView}
</div>
);
diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss
new file mode 100644
index 000000000..0144625c1
--- /dev/null
+++ b/src/client/views/collections/CollectionPDFView.scss
@@ -0,0 +1,27 @@
+.collectionPdfView-buttonTray {
+ top : 25px;
+ left : 20px;
+ position: relative;
+ transform-origin: left top;
+ position: absolute;
+}
+.collectionPdfView-cont{
+ width: 100%;
+ height: 100%;
+ position: absolute;
+
+}
+.collectionPdfView-backward {
+ color : white;
+ top :0px;
+ left : 0px;
+ position: absolute;
+ background-color: rgba(50, 50, 50, 0.2);
+}
+.collectionPdfView-forward {
+ color : white;
+ top :0px;
+ left : 35px;
+ position: absolute;
+ background-color: rgba(50, 50, 50, 0.2);
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index f22c07060..124d82c8b 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,10 +1,11 @@
-import { action, computed } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
import { ContextMenu } from "../ContextMenu";
import { CollectionView, CollectionViewType } from "./CollectionView";
import { CollectionViewProps } from "./CollectionViewBase";
+import "./CollectionPDFView.scss"
import React = require("react");
import { FieldId } from "../../../fields/Field";
@@ -18,22 +19,23 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> {
isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
}
- public SelectedDocs: FieldId[] = []
- @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0;
- @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0;
+ private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); }
+ private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); }
+ @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1;
+ @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1;
- @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); }
- @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); }
- @computed private get uIButtons() {
+ private get uIButtons() {
+ let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]);
return (
- <div className="pdfBox-buttonTray" key="tray">
- <button className="pdfButton" onClick={this.onPageBack}>{"<"}</button>
- <button className="pdfButton" onClick={this.onPageForward}>{">"}</button>
+ <div className="collectionPdfView-buttonTray" key="tray" style={{ transform: `scale(${scaling}, ${scaling})` }}>
+ <button className="collectionPdfView-backward" onClick={this.onPageBack}>{"<"}</button>
+ <button className="collectionPdfView-forward" onClick={this.onPageForward}>{">"}</button>
</div>);
}
// "inherited" CollectionView API starts here...
-
+ @observable
+ public SelectedDocs: FieldId[] = []
public active: () => boolean = () => CollectionView.Active(this);
addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
@@ -49,7 +51,7 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> {
get subView(): any { return CollectionView.SubView(this); }
render() {
- return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}>
+ return (<div className="collectionPdfView-cont" onContextMenu={this.specificContextMenu}>
{this.subView}
{this.props.isSelected() ? this.uIButtons : (null)}
</div>)
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index d40e6d314..0d615dc01 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -1,185 +1,162 @@
-
+@import "../global_variables";
.collectionSchemaView-container {
- border-style: solid;
+ border: 1px solid $intermediate-color;
+ border-radius: $border-radius;
+ box-sizing: border-box;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+
+.collectionSchemaView-content {
+ position: absolute;
+ height:100%;
+ width:100%;
+ overflow:auto;
+}
+ .collectionSchemaView-previewRegion {
+ position: relative;
+ background: $light-color;
+ float: left;
+ height: 100%;
+ }
+ .collectionSchemaView-previewHandle {
+ position: absolute;
+ height: 37px;
+ width: 20px;
+ z-index: 20;
+ right: 0;
+ top: 0;
+ background: $main-accent;
+ }
+ .collectionSchemaView-dividerDragger {
+ position: relative;
box-sizing: border-box;
+ border-left: 1px solid $intermediate-color;
+ border-right: 1px solid $intermediate-color;
+ float: left;
+ height: 100%;
+ }
+ .collectionSchemaView-tableContainer {
+ position: relative;
+ float: left;
+ height: 100%;
+ }
+
+ .ReactTable {
position: absolute;
+ // display: inline-block;
+ // overflow: auto;
width: 100%;
height: 100%;
- .collectionSchemaView-previewRegion {
- position: relative;
- background: black;
- float: left;
- height: 100%;
- }
- .collectionSchemaView-previewHandle {
- position: absolute;
- height: 37px;
- width: 20px;
- z-index: 20;
- right: 0;
- top: 0;
- background: Black ;
- }
- .collectionSchemaView-dividerDragger{
- position: relative;
- background: black;
- float: left;
- height: 100%;
- }
- .collectionSchemaView-tableContainer {
+ background: $light-color;
+ box-sizing: border-box;
+ border: none !important;
+ .rt-table {
+ overflow-y: auto;
+ overflow-x: auto;
+ height: 100%;
+ display: -webkit-inline-box;
+ direction: ltr;
+ // direction:rtl;
+ // display:block;
+ }
+ .rt-tbody {
+ //direction: ltr;
+ direction: rtl;
+ }
+ .rt-tr-group {
+ direction: ltr;
+ max-height: 44px;
+ }
+ .rt-td {
+ border-width: 1px;
+ border-right-color: $intermediate-color;
+ .imageBox-cont {
position: relative;
- float: left;
- height: 100%;
- }
-
- .ReactTable {
- position: absolute;
- // display: inline-block;
- // overflow: auto;
- width: 100%;
+ max-height: 100%;
+ }
+ .imageBox-cont img {
+ object-fit: contain;
+ max-width: 100%;
height: 100%;
- background: white;
- box-sizing: border-box;
- .rt-table {
- overflow-y: auto;
- overflow-x: auto;
- height: 100%;
-
- display: -webkit-inline-box;
- direction: ltr;
- // direction:rtl;
- // display:block;
- }
- .rt-tbody {
- //direction: ltr;
- direction: rtl;
- }
- .rt-tr-group {
- direction: ltr;
- max-height: 44px;
- }
- .rt-td {
- border-width: 1;
- border-right-color: #aaa;
- .imageBox-cont {
- position:relative;
- max-height:100%;
- }
- .imageBox-cont img {
- object-fit: contain;
- max-width: 100%;
- height: 100%
- }
- }
- .rt-tr-group {
- border-width: 1;
- border-bottom-color: #aaa
- }
- }
- .ReactTable .rt-thead.-header {
- background:grey;
- }
- .ReactTable .rt-th, .ReactTable .rt-td {
- max-height: 44;
- padding: 3px 7px;
- }
- .ReactTable .rt-tbody .rt-tr-group:last-child {
- border-bottom: grey;
- border-bottom-style: solid;
- border-bottom-width: 1;
- }
- .documentView-node:first-child {
- background: grey;
- .imageBox-cont img {
- object-fit: contain;
- }
- }
+ }
+ .videobox-cont {
+ object-fit: contain;
+ width:auto;
+ height: 100%;
+ }
+ }
+ }
+ .ReactTable .rt-thead.-header {
+ background: $intermediate-color;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 12px;
+ height: 30px;
+ padding-top: 4px;
+ }
+ .ReactTable .rt-th,
+ .ReactTable .rt-td {
+ max-height: 44;
+ padding: 3px 7px;
+ font-size: 13px;
+ text-align: center;
+ }
+ .ReactTable .rt-tbody .rt-tr-group:last-child {
+ border-bottom: $intermediate-color;
+ border-bottom-style: solid;
+ border-bottom-width: 1;
+ }
+ .documentView-node:first-child {
+ background: $light-color;
+ .imageBox-cont img {
+ object-fit: contain;
+ }
+ }
}
.Resizer {
- box-sizing: border-box;
- background: #000;
- opacity: 0.5;
- z-index: 1;
- background-clip: padding-box;
- &.horizontal {
- height: 11px;
- margin: -5px 0;
- border-top: 5px solid rgba(255, 255, 255, 0);
- border-bottom: 5px solid rgba(255, 255, 255, 0);
- cursor: row-resize;
- width: 100%;
- &:hover {
- border-top: 5px solid rgba(0, 0, 0, 0.5);
- border-bottom: 5px solid rgba(0, 0, 0, 0.5);
- }
- }
- &.vertical {
- width: 11px;
- margin: 0 -5px;
- border-left: 5px solid rgba(255, 255, 255, 0);
- border-right: 5px solid rgba(255, 255, 255, 0);
- cursor: col-resize;
- &:hover {
- border-left: 5px solid rgba(0, 0, 0, 0.5);
- border-right: 5px solid rgba(0, 0, 0, 0.5);
- }
- }
+ box-sizing: border-box;
+ background: #000;
+ opacity: 0.5;
+ z-index: 1;
+ background-clip: padding-box;
+ &.horizontal {
+ height: 11px;
+ margin: -5px 0;
+ border-top: 5px solid rgba(255, 255, 255, 0);
+ border-bottom: 5px solid rgba(255, 255, 255, 0);
+ cursor: row-resize;
+ width: 100%;
&:hover {
- -webkit-transition: all 2s ease;
- transition: all 2s ease;
- }
+ border-top: 5px solid rgba(0, 0, 0, 0.5);
+ border-bottom: 5px solid rgba(0, 0, 0, 0.5);
+ }
+ }
+ &.vertical {
+ width: 11px;
+ margin: 0 -5px;
+ border-left: 5px solid rgba(255, 255, 255, 0);
+ border-right: 5px solid rgba(255, 255, 255, 0);
+ cursor: col-resize;
+ &:hover {
+ border-left: 5px solid rgba(0, 0, 0, 0.5);
+ border-right: 5px solid rgba(0, 0, 0, 0.5);
+ }
+ }
+ &:hover {
+ -webkit-transition: all 2s ease;
+ transition: all 2s ease;
+ }
}
.vertical {
- section {
- width: 100vh;
- height: 100vh;
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-orient: vertical;
- -webkit-box-direction: normal;
- -webkit-flex-direction: column;
- -ms-flex-direction: column;
- flex-direction: column;
- }
- header {
- padding: 1rem;
- background: #eee;
- }
- footer {
- padding: 1rem;
- background: #eee;
- }
-}
-
-.horizontal {
- section {
- width: 100vh;
- height: 100vh;
- display: flex;
- flex-direction: column;
- }
- header {
- padding: 1rem;
- background: #eee;
- }
- footer {
- padding: 1rem;
- background: #eee;
- }
-}
-
-.parent {
- width: 100%;
- height: 100%;
- -webkit-box-flex: 1;
- -webkit-flex: 1;
- -ms-flex: 1;
- flex: 1;
+ section {
+ width: 100vh;
+ height: 100vh;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@@ -189,19 +166,71 @@
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
+ }
+ header {
+ padding: 1rem;
+ background: #eee;
+ }
+ footer {
+ padding: 1rem;
+ background: #eee;
+ }
+}
+
+.horizontal {
+ section {
+ width: 100vh;
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+ header {
+ padding: 1rem;
+ background: #eee;
+ }
+ footer {
+ padding: 1rem;
+ background: #eee;
+ }
+}
+
+.parent {
+ width: 100%;
+ height: 100%;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
}
.header {
- background: #aaa;
- height: 3rem;
- line-height: 3rem;
+ background: #aaa;
+ height: 3rem;
+ line-height: 3rem;
}
.wrapper {
- background: #ffa;
- margin: 5rem;
- -webkit-box-flex: 1;
- -webkit-flex: 1;
- -ms-flex: 1;
- flex: 1;
-} \ No newline at end of file
+ background: #ffa;
+ margin: 5rem;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+}
+
+.-even {
+ background: $light-color !important;
+}
+
+.-odd {
+ background: $light-color-secondary !important;
+}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 04f017378..8c1aeef2c 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,5 +1,5 @@
import React = require("react")
-import { action, observable } from "mobx";
+import { action, observable, computed } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
@@ -24,14 +24,14 @@ import { setupDrag } from "../../util/DragManager";
@observer
export class CollectionSchemaView extends CollectionViewBase {
private _mainCont = React.createRef<HTMLDivElement>();
- private DIVIDER_WIDTH = 5;
+ private DIVIDER_WIDTH = 4;
@observable _contentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ContentScaling prop of the DocumentView
@observable _dividerX = 0;
@observable _panelWidth = 0;
@observable _panelHeight = 0;
@observable _selectedIndex = 0;
- @observable _splitPercentage: number = 50;
+ @computed get splitPercentage() { return this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0); }
renderCell = (rowProps: CellInfo) => {
let props: FieldViewProps = {
@@ -49,7 +49,7 @@ export class CollectionSchemaView extends CollectionViewBase {
let reference = React.createRef<HTMLDivElement>();
let onItemDown = setupDrag(reference, () => props.doc);
return (
- <div onPointerDown={onItemDown} key={props.doc.Id} ref={reference}>
+ <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "36px" }} key={props.doc.Id} ref={reference}>
<EditableView contents={contents}
height={36} GetValue={() => {
let field = props.doc.Get(props.fieldKey);
@@ -89,7 +89,8 @@ export class CollectionSchemaView extends CollectionViewBase {
return {
onClick: action((e: React.MouseEvent, handleOriginal: Function) => {
that._selectedIndex = rowInfo.index;
- this._splitPercentage += 0.05; // bcz - ugh - needed to force Measure to do its thing and call onResize
+ // bcz - ugh - needed to force Measure to do its thing and call onResize
+ this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage - 0.05)
if (handleOriginal) {
handleOriginal()
@@ -106,18 +107,18 @@ export class CollectionSchemaView extends CollectionViewBase {
@action
onDividerMove = (e: PointerEvent): void => {
let nativeWidth = this._mainCont.current!.getBoundingClientRect();
- this._splitPercentage = Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100);
+ this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100));
}
@action
onDividerUp = (e: PointerEvent): void => {
document.removeEventListener("pointermove", this.onDividerMove);
document.removeEventListener('pointerup', this.onDividerUp);
- if (this._startSplitPercent == this._splitPercentage) {
- this._splitPercentage = this._splitPercentage == 1 ? 66 : 100;
+ if (this._startSplitPercent == this.splitPercentage) {
+ this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0);
}
}
onDividerDown = (e: React.PointerEvent) => {
- this._startSplitPercent = this._splitPercentage;
+ this._startSplitPercent = this.splitPercentage;
e.stopPropagation();
e.preventDefault();
document.addEventListener("pointermove", this.onDividerMove);
@@ -134,12 +135,12 @@ export class CollectionSchemaView extends CollectionViewBase {
e.preventDefault();
document.removeEventListener("pointermove", this.onExpanderMove);
document.removeEventListener('pointerup', this.onExpanderUp);
- if (this._startSplitPercent == this._splitPercentage) {
- this._splitPercentage = this._splitPercentage == 100 ? 66 : 100;
+ if (this._startSplitPercent == this.splitPercentage) {
+ this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0);
}
}
onExpanderDown = (e: React.PointerEvent) => {
- this._startSplitPercent = this._splitPercentage;
+ this._startSplitPercent = this.splitPercentage;
e.stopPropagation();
e.preventDefault();
document.addEventListener("pointermove", this.onExpanderMove);
@@ -203,7 +204,7 @@ export class CollectionSchemaView extends CollectionViewBase {
)
let previewHandle = !this.props.active() ? (null) : (
<div className="collectionSchemaView-previewHandle" onPointerDown={this.onExpanderDown} />);
- let dividerDragger = this._splitPercentage == 100 ? (null) :
+ let dividerDragger = this.splitPercentage == 0 ? (null) :
<div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} />
return (
<div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} ref={this._mainCont} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} >
@@ -213,7 +214,8 @@ export class CollectionSchemaView extends CollectionViewBase {
this._panelHeight = r.entry.height;
})}>
{({ measureRef }) =>
- <div ref={measureRef} className="collectionSchemaView-tableContainer" style={{ width: `${this._splitPercentage}%` }}>
+ <div ref={measureRef} className="collectionSchemaView-tableContainer"
+ style={{ width: `calc(100% - ${this.splitPercentage}%)` }}>
<ReactTable
data={children}
pageSize={children.length}
@@ -235,7 +237,7 @@ export class CollectionSchemaView extends CollectionViewBase {
}
</Measure>
{dividerDragger}
- <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${100 - this._splitPercentage}% - ${this.DIVIDER_WIDTH}px)` }}>
+ <div className="collectionSchemaView-previewRegion" style={{ width: `calc(${this.props.Document.GetNumber(KeyStore.SchemaSplitPercentage, 0)}% - ${this.DIVIDER_WIDTH}px)` }}>
{content}
</div>
{previewHandle}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index f8d580a7b..fa0f1c761 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -1,16 +1,25 @@
+@import "../global_variables";
#body {
padding: 20px;
- background: #bbbbbb;
+ background: $light-color-secondary;
+ font-size: 13px;
+ overflow: scroll;
}
ul {
list-style: none;
+ padding-left: 20px;
}
li {
margin: 5px 0;
}
+.collection-child {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
.no-indent {
padding-left: 0;
}
@@ -18,10 +27,17 @@ li {
.bullet {
width: 1.5em;
display: inline-block;
+ color: $intermediate-color;
+}
+
+.coll-title {
+ font-size: 24px;
+ margin-bottom: 20px;
}
.collectionTreeView-dropTarget {
- border-style: solid;
+ border: 0px solid transparent;
+ border-radius: $border-radius;
box-sizing: border-box;
height: 100%;
}
@@ -30,8 +46,16 @@ li {
display: inline-table;
}
+.docContainer:hover {
+ .delete-button {
+ display: inline;
+ }
+}
+
.delete-button {
- color: #999999;
+ color: $intermediate-color;
float: right;
- margin-left: 1em;
+ margin-left: 15px;
+ margin-top: 3px;
+ display: none;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8b06d9ac4..80fc89712 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -12,6 +12,10 @@ import { setupDrag } from "../../util/DragManager";
import { FieldWaiting } from "../../../fields/Field";
import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faTrashAlt, faCaretRight, faCaretDown } from '@fortawesome/free-solid-svg-icons';
+
export interface TreeViewProps {
document: Document;
deleteDoc: (doc: Document) => void;
@@ -23,6 +27,10 @@ export enum BulletType {
List
}
+library.add(faTrashAlt);
+library.add(faCaretDown);
+library.add(faCaretRight);
+
@observer
/**
* Component that takes in a document prop and a boolean whether it's collapsed or not.
@@ -50,11 +58,11 @@ class TreeView extends React.Component<TreeViewProps> {
switch (type) {
case BulletType.Collapsed:
- return <div className="bullet" onClick={onClicked}>&#9654;</div>
+ return <div className="bullet" onClick={onClicked}><FontAwesomeIcon icon="caret-right" /></div>
case BulletType.Collapsible:
- return <div className="bullet" onClick={onClicked}>&#9660;</div>
+ return <div className="bullet" onClick={onClicked}><FontAwesomeIcon icon="caret-down" /></div>
case BulletType.List:
- return <div className="bullet">&mdash;</div>
+ return <div className="bullet"></div>
}
}
@@ -79,7 +87,7 @@ class TreeView extends React.Component<TreeViewProps> {
this.props.document.SetData(KeyStore.Title, value, TextField);
return true;
}} />
- <div className="delete-button" onClick={this.delete}>x</div>
+ <div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>
</div >
}
@@ -101,7 +109,7 @@ class TreeView extends React.Component<TreeViewProps> {
<TreeView document={value} deleteDoc={this.remove} />)
)
subView =
- <li key={this.props.document.Id} >
+ <li className="collection-child" key={this.props.document.Id} >
{this.renderBullet(BulletType.Collapsible)}
{titleElement}
<ul key={this.props.document.Id}>
@@ -109,7 +117,7 @@ class TreeView extends React.Component<TreeViewProps> {
</ul>
</li>
} else {
- subView = <li key={this.props.document.Id}>
+ subView = <li className="collection-child" key={this.props.document.Id}>
{this.renderBullet(BulletType.Collapsed)}
{titleElement}
</li>
@@ -157,7 +165,7 @@ export class CollectionTreeView extends CollectionViewBase {
return (
<div id="body" className="collectionTreeView-dropTarget" onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}>
- <h3>
+ <div className="coll-title">
<EditableView contents={titleStr}
height={72} GetValue={() => {
return this.props.Document.Title;
@@ -165,7 +173,8 @@ export class CollectionTreeView extends CollectionViewBase {
this.props.Document.SetData(KeyStore.Title, value, TextField);
return true;
}} />
- </h3>
+ </div>
+ <hr />
<ul className="no-indent">
{childrenElement}
</ul>
diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss
new file mode 100644
index 000000000..cbb981b13
--- /dev/null
+++ b/src/client/views/collections/CollectionVideoView.scss
@@ -0,0 +1,40 @@
+
+.collectionVideoView-cont{
+ width: 100%;
+ height: 100%;
+ position: absolute;
+
+}
+.collectionVideoView-time{
+ color : white;
+ top :25px;
+ left : 25px;
+ position: absolute;
+ background-color: rgba(50, 50, 50, 0.2);
+ transform-origin: left top;
+}
+.collectionVideoView-play {
+ width: 25px;
+ height: 20px;
+ bottom: 25px;
+ left : 25px;
+ position: absolute;
+ color : white;
+ background-color: rgba(50, 50, 50, 0.2);
+ border-radius: 4px;
+ text-align: center;
+ transform-origin: left bottom;
+}
+.collectionVideoView-full {
+ width: 25px;
+ height: 20px;
+ bottom: 25px;
+ right : 25px;
+ position: absolute;
+ color : white;
+ background-color: rgba(50, 50, 50, 0.2);
+ border-radius: 4px;
+ text-align: center;
+ transform-origin: right bottom;
+
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index a6471f53c..b64ef3c07 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
@@ -7,6 +7,7 @@ import { CollectionView, CollectionViewType } from "./CollectionView";
import { CollectionViewProps } from "./CollectionViewBase";
import React = require("react");
import { FieldId } from "../../../fields/Field";
+import "./CollectionVideoView.scss"
@observer
@@ -18,14 +19,29 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> {
isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
}
- public SelectedDocs: FieldId[] = []
- @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0;
- @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0;
+ private _mainCont = React.createRef<HTMLDivElement>();
+
+ private get uIButtons() {
+ let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]);
+ return ([
+ <div className="collectionVideoView-time" key="time" onPointerDown={this.onResetDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
+ <span>{"" + Math.round(this.ctime)}</span>
+ <span style={{ fontSize: 8 }}>{" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)}</span>
+ </div>,
+ <div className="collectionVideoView-play" key="play" onPointerDown={this.onPlayDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
+ {this.playing ? "\"" : ">"}
+ </div>,
+ <div className="collectionVideoView-full" key="full" onPointerDown={this.onFullDown} style={{ transform: `scale(${scaling}, ${scaling})` }}>
+ F
+ </div>
+ ]);
+ }
+
- @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); }
- @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); }
// "inherited" CollectionView API starts here...
+ @observable
+ public SelectedDocs: FieldId[] = []
public active: () => boolean = () => CollectionView.Active(this);
addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
@@ -40,11 +56,63 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> {
get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; }
get subView(): any { return CollectionView.SubView(this); }
+ componentDidMount() {
+ this.updateTimecode();
+ }
+
+ get player(): HTMLVideoElement | undefined {
+ return this._mainCont.current ? this._mainCont.current.getElementsByTagName("video")[0] : undefined;
+ }
+
+ @action
+ updateTimecode = () => {
+ if (this.player) {
+ this.ctime = this.player.currentTime;
+ this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this.ctime));
+ }
+ setTimeout(() => this.updateTimecode(), 100)
+ }
+
+
+ @observable
+ ctime: number = 0
+ @observable
+ playing: boolean = false;
+
+ @action
+ onPlayDown = () => {
+ if (this.player) {
+ if (this.player.paused) {
+ this.player.play();
+ this.playing = true;
+ } else {
+ this.player.pause();
+ this.playing = false;
+ }
+ }
+ }
+ @action
+ onFullDown = (e: React.PointerEvent) => {
+ if (this.player) {
+ this.player.requestFullscreen();
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+
+ @action
+ onResetDown = () => {
+ if (this.player) {
+ this.player.pause();
+ this.player.currentTime = 0;
+ }
+
+ }
+
render() {
- return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}>
- {/* <video controls className="videobox-cont"> */}
+ return (<div className="collectionVideoView-cont" ref={this._mainCont} onContextMenu={this.specificContextMenu}>
{this.subView}
- {/* </video> */}
+ {this.uIButtons}
</div>)
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 17a0fbd23..d9b2722a6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -22,20 +22,19 @@ export enum CollectionViewType {
Tree
}
-export const COLLECTION_BORDER_WIDTH = 2;
+export const COLLECTION_BORDER_WIDTH = 1;
@observer
export class CollectionView extends React.Component<CollectionViewProps> {
- @observable
- public SelectedDocs: FieldId[] = [];
-
public static LayoutString(fieldKey: string = "DataKey") {
return `<${CollectionView.name} Document={Document}
ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
}
+ @observable
+ public SelectedDocs: FieldId[] = [];
public active: () => boolean = () => CollectionView.Active(this);
addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
@@ -50,7 +49,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
@action
public static AddDocument(props: CollectionViewProps, doc: Document) {
- doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, 0));
+ doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1));
if (props.Document.Get(props.fieldKey) instanceof Field) {
//TODO This won't create the field if it doesn't already exist
const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx
index d9e4df1e9..65aaa837f 100644
--- a/src/client/views/collections/MarqueeView.tsx
+++ b/src/client/views/collections/MarqueeView.tsx
@@ -3,21 +3,22 @@ import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { FieldWaiting, Opt } from "../../../fields/Field";
import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
import { Documents } from "../../documents/Documents";
import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
import { CollectionFreeFormView } from "./CollectionFreeFormView";
import "./MarqueeView.scss";
import React = require("react");
-
+import { InkField, StrokeData } from "../../../fields/InkField";
+import { Utils } from "../../../Utils";
+import { InkingCanvas } from "../InkingCanvas";
interface MarqueeViewProps {
getMarqueeTransform: () => Transform;
getTransform: () => Transform;
container: CollectionFreeFormView;
addDocument: (doc: Document) => void;
- activeDocuemnts: () => Document[];
+ activeDocuments: () => Document[];
selectDocuments: (docs: Document[]) => void;
removeDocument: (doc: Document) => boolean;
}
@@ -92,31 +93,59 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
@action
marqueeCommand = (e: KeyboardEvent) => {
- if (e.key == "Backspace") {
+ if (e.key == "Backspace" || e.key == "Delete") {
this.marqueeSelect().map(d => this.props.removeDocument(d));
+ this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField);
this.cleanupInteractions();
}
if (e.key == "c") {
let bounds = this.Bounds;
- let selected = this.marqueeSelect().map(m => m);
- this.marqueeSelect().map(d => this.props.removeDocument(d));
- //setTimeout(() => {
- this.props.addDocument(Documents.FreeformDocument(selected.map(d => {
+ let selected = this.marqueeSelect().map(d => {
+ this.props.removeDocument(d);
d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
d.SetNumber(KeyStore.Page, 0);
d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0));
return d;
- }), { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, height: bounds.height, title: "a nested collection" }));
+ });
+ let liftedInk = this.marqueeInkSelect(true);
+ this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField);
+ //setTimeout(() => {
+ this.props.addDocument(Documents.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, backgroundColor: "Transparent", height: bounds.height, ink: liftedInk, title: "a nested collection" }));
// }, 100);
this.cleanupInteractions();
}
}
+ marqueeInkSelect(select: boolean) {
+ let selRect = this.Bounds;
+ let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
+ let centerShiftY = 0 - (selRect.top + selRect.height / 2);
+ let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
+ if (ink && ink != FieldWaiting) {
+ let idata = new Map();
+ ink.Data.forEach((value: StrokeData, key: string, map: any) => {
+ let inside = InkingCanvas.IntersectStrokeRect(value, selRect);
+ if (inside && select) {
+ idata.set(key,
+ {
+ pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }),
+ color: value.color,
+ width: value.width,
+ tool: value.tool,
+ page: -1
+ });
+ } else if (!inside && !select) {
+ idata.set(key, value);
+ }
+ })
+ return idata;
+ }
+ }
marqueeSelect() {
let selRect = this.Bounds;
let selection: Document[] = [];
- this.props.activeDocuemnts().map(doc => {
+ this.props.activeDocuments().map(doc => {
var x = doc.GetNumber(KeyStore.X, 0);
var y = doc.GetNumber(KeyStore.Y, 0);
var w = doc.GetNumber(KeyStore.Width, 0);
diff --git a/src/client/views/collections/PreviewCursor.tsx b/src/client/views/collections/PreviewCursor.tsx
index ab68fbc46..a1411250a 100644
--- a/src/client/views/collections/PreviewCursor.tsx
+++ b/src/client/views/collections/PreviewCursor.tsx
@@ -16,7 +16,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView";
export interface PreviewCursorProps {
getTransform: () => Transform;
container: CollectionFreeFormView;
- addLiveTextDocuemnt: (doc: Document) => void;
+ addLiveTextDocument: (doc: Document) => void;
}
@observer
@@ -57,11 +57,13 @@ export class PreviewCursor extends React.Component<PreviewCursorProps> {
@action
onKeyPress = (e: KeyboardEvent) => {
//if not these keys, make a textbox if preview cursor is active!
- if (!e.ctrlKey && !e.altKey) {
+ if (!e.ctrlKey && !e.altKey && !e.defaultPrevented) {
//make textbox and add it to this collection
let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY);
let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "new" });
- this.props.addLiveTextDocuemnt(newBox);
+ this.props.addLiveTextDocument(newBox);
+ e.stopPropagation();
+ e.preventDefault();
}
}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index f7d89843d..6daf15f5f 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -18,7 +18,7 @@ export class AudioBox extends React.Component<FieldViewProps> {
super(props);
}
-
+
componentDidMount() {
}
@@ -26,16 +26,16 @@ export class AudioBox extends React.Component<FieldViewProps> {
componentWillUnmount() {
}
-
+
render() {
let field = this.props.doc.Get(this.props.fieldKey)
- let path = field == FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3":
+ let path = field == FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" :
field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3";
-
+
return (
<div>
- <audio controls className = "audiobox-cont">
- <source src = {path} type="audio/mpeg"/>
+ <audio controls className="audiobox-cont">
+ <source src={path} type="audio/mpeg" />
Not supported.
</audio>
</div>
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
new file mode 100644
index 000000000..55b4938a0
--- /dev/null
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -0,0 +1,35 @@
+import { Document } from "../../../fields/Document";
+import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionSchemaView } from "../collections/CollectionSchemaView";
+import { CollectionView, CollectionViewType } from "../collections/CollectionView";
+import { CollectionPDFView } from "../collections/CollectionPDFView";
+import { CollectionVideoView } from "../collections/CollectionVideoView";
+import { FormattedTextBox } from "../nodes/FormattedTextBox";
+import { ImageBox } from "../nodes/ImageBox";
+import { VideoBox } from "../nodes/VideoBox";
+import { AudioBox } from "../nodes/AudioBox";
+import { KeyValueBox } from "./KeyValueBox"
+import { WebBox } from "../nodes/WebBox";
+import { PDFBox } from "../nodes/PDFBox";
+import "./DocumentView.scss";
+import React = require("react");
+const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
+
+interface JsxBindings {
+ Document: Document;
+ layout: string;
+ [prop: string]: any;
+}
+
+export class DocumentContentsView extends React.PureComponent<JsxBindings> {
+ render() {
+ return <JsxParser
+ components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
+ bindings={this.props}
+ jsx={this.props.layout}
+ showWarnings={true}
+ onError={(test: any) => { console.log(test) }}
+ />
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index ab913897b..85a115f1c 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,23 +1,23 @@
+@import "../global_variables";
.documentView-node {
- position: absolute;
- background: #cdcdcd;
- //overflow: hidden;
- &.minimized {
- width: 30px;
- height: 30px;
- }
- .top {
- background: #232323;
- height: 20px;
- cursor: pointer;
- }
- .content {
- padding: 20px 20px;
- height: auto;
- box-sizing: border-box;
- }
- .scroll-box {
- overflow-y: scroll;
- height: calc(100% - 20px);
- }
-} \ No newline at end of file
+ position: absolute;
+ background: $light-color; //overflow: hidden;
+ &.minimized {
+ width: 30px;
+ height: 30px;
+ }
+ .top {
+ background: #232323;
+ height: 20px;
+ cursor: pointer;
+ }
+ .content {
+ padding: 20px 20px;
+ height: auto;
+ box-sizing: border-box;
+ }
+ .scroll-box {
+ overflow-y: scroll;
+ height: calc(100% - 20px);
+ }
+}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8ff355a15..96a9ff2a8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,32 +1,22 @@
-import { action, computed, IReactionDisposer, runInAction, reaction, trace } from "mobx";
+import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../fields/Document";
import { Field, FieldWaiting, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
+import { TextField } from "../../../fields/TextField";
+import { Documents } from "../../documents/Documents";
+import { DocumentManager } from "../../util/DocumentManager";
import { DragManager } from "../../util/DragManager";
import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
import { CollectionView, CollectionViewType } from "../collections/CollectionView";
-import { CollectionPDFView } from "../collections/CollectionPDFView";
-import { CollectionVideoView } from "../collections/CollectionVideoView";
import { ContextMenu } from "../ContextMenu";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
-import { ImageBox } from "../nodes/ImageBox";
-import { VideoBox } from "../nodes/VideoBox";
-import { AudioBox } from "../nodes/AudioBox";
-import { Documents } from "../../documents/Documents"
-import { KeyValueBox } from "./KeyValueBox"
-import { WebBox } from "../nodes/WebBox";
-import { PDFBox } from "../nodes/PDFBox";
import "./DocumentView.scss";
import React = require("react");
-import { TextField } from "../../../fields/TextField";
-import { DocumentManager } from "../../util/DocumentManager";
+import { DocumentContentsView } from "./DocumentContentsView";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -339,9 +329,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
var scaling = this.props.ContentScaling();
var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
+ var backgroundcolor = this.props.Document.GetText(KeyStore.BackgroundColor, "");
return (
<div className="documentView-node" ref={this._mainCont}
style={{
+ background: backgroundcolor,
width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
transformOrigin: "left top",
diff --git a/src/client/views/nodes/FieldTextBox.scss b/src/client/views/nodes/FieldTextBox.scss
index b6ce2fabc..d2cd61b0d 100644
--- a/src/client/views/nodes/FieldTextBox.scss
+++ b/src/client/views/nodes/FieldTextBox.scss
@@ -1,14 +1,14 @@
.ProseMirror {
- margin-top: -1em;
- width: 100%;
- height: 100%;
+ margin-top: -1em;
+ width: 100%;
+ height: 100%;
}
.ProseMirror:focus {
- outline: none !important
+ outline: none !important;
}
.fieldTextBox-cont {
- background: white;
- padding: 1vw;
-} \ No newline at end of file
+ background: white;
+ padding: 1vw;
+}
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index ab5849f09..32da2632e 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -1,38 +1,46 @@
+@import "../global_variables";
.ProseMirror {
- width: 100%;
- height: auto;
- min-height: 100%
+ width: 100%;
+ height: auto;
+ min-height: 100%;
+ font-family: $serif;
}
.ProseMirror:focus {
- outline: none !important
+ outline: none !important;
}
.formattedTextBox-cont {
- background: white;
- padding: 1;
- border-width: 1px;
- border-radius: 2px;
- border-color:black;
- box-sizing: border-box;
- background: white;
- border-style:solid;
- overflow-y: scroll;
- overflow-x: hidden;
- color: initial;
- height: 100%;
+ background: $light-color-secondary;
+ padding: 0.9em;
+ border-width: 0px;
+ border-radius: $border-radius;
+ border-color: $intermediate-color;
+ box-sizing: border-box;
+ border-style: solid;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ color: initial;
+ height: 100%;
}
.menuicon {
- display: inline-block;
- border-right: 1px solid rgba(0, 0, 0, 0.2);
- color: #888;
- line-height: 1;
- padding: 0 7px;
- margin: 1px;
- cursor: pointer;
- text-align: center;
- min-width: 1.4em;
- }
- .strong, .heading { font-weight: bold; }
- .em { font-style: italic; } \ No newline at end of file
+ display: inline-block;
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
+ color: #888;
+ line-height: 1;
+ padding: 0 7px;
+ margin: 1px;
+ cursor: pointer;
+ text-align: center;
+ min-width: 1.4em;
+}
+
+.strong,
+.heading {
+ font-weight: bold;
+}
+
+.em {
+ font-style: italic;
+}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5c7aaf9fe..f5d4c030b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -31,7 +31,7 @@ import { ContextMenu } from "../../views/ContextMenu";
// and 'doc' property to the document that is being rendered
//
// When rendered() by React, this extracts the TextController from the Document stored at the
-// specified Key and assigns it to an HTML input node. When changes are made tot his node,
+// specified Key and assigns it to an HTML input node. When changes are made to this node,
// this will edit the document and assign the new value to that field.
//]
export class FormattedTextBox extends React.Component<FieldViewProps> {
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 31452bc85..487038841 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -1,12 +1,11 @@
-
.imageBox-cont {
- padding: 0vw;
- position: relative;
- text-align: center;
- width: 100%;
- height: auto;
- max-width: 100%;
- max-height: 100%
+ padding: 0vw;
+ position: relative;
+ text-align: center;
+ width: 100%;
+ height: auto;
+ max-width: 100%;
+ max-height: 100%;
}
.imageBox-cont img {
@@ -15,8 +14,8 @@
}
.imageBox-button {
- padding : 0vw;
- border: none;
- width : 100%;
- height: 100%;
-} \ No newline at end of file
+ padding: 0vw;
+ border: none;
+ width: 100%;
+ height: 100%;
+}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index bceeedbc6..cad8904d0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -70,7 +70,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
}
lightbox = (path: string) => {
- const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"];
+ const images = [path];
if (this._isOpen && this.props.isSelected()) {
return (<Lightbox
mainSrc={images[this._photoIndex]}
diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss
index 1295266e5..e946275fa 100644
--- a/src/client/views/nodes/KeyValueBox.scss
+++ b/src/client/views/nodes/KeyValueBox.scss
@@ -1,31 +1,31 @@
.keyValueBox-cont {
- overflow-y:scroll;
- height: 100%;
- border: black;
- border-width: 1px;
- border-style: solid;
- box-sizing: border-box;
- display: inline-block;
- .imageBox-cont img {
- max-height:45px;
- height: auto;
- }
+ overflow-y: scroll;
+ height: 100%;
+ border: black;
+ border-width: 1px;
+ border-style: solid;
+ box-sizing: border-box;
+ display: inline-block;
+ .imageBox-cont img {
+ max-height: 45px;
+ height: auto;
+ }
}
.keyValueBox-table {
- position: relative;
+ position: relative;
}
.keyValueBox-header {
- background:gray;
+ background: gray;
}
.keyValueBox-evenRow {
+ background: white;
+ .formattedTextBox-cont {
background: white;
- .formattedTextBox-cont {
- background: white;
- }
+ }
}
.keyValueBox-oddRow {
- background: lightGray;
- .formattedTextBox-cont {
- background: lightgray;
- }
-} \ No newline at end of file
+ background: lightGray;
+ .formattedTextBox-cont {
+ background: lightgray;
+ }
+}
diff --git a/src/client/views/nodes/LinkBox.scss b/src/client/views/nodes/LinkBox.scss
index 00e5ebb3d..5d5f782d2 100644
--- a/src/client/views/nodes/LinkBox.scss
+++ b/src/client/views/nodes/LinkBox.scss
@@ -1,13 +1,14 @@
+@import "../global_variables";
.link-container {
width: 100%;
- height: 30px;
+ height: 35px;
display: flex;
flex-direction: row;
border-top: 0.5px solid #bababa;
}
.info-container {
- width: 60%;
+ width: 55%;
padding-top: 5px;
padding-left: 5px;
display: flex;
@@ -23,17 +24,42 @@
}
.button-container {
- width: 40%;
+ width: 45%;
display: flex;
flex-direction: row;
}
.button {
- height: 15px;
- width: 15px;
- margin: 8px 5px;
+ height: 20px;
+ width: 20px;
+ margin: 8px 4px;
border-radius: 50%;
- opacity: 0.6;
+ opacity: 0.9;
pointer-events: auto;
- background-color: #2B6091;
+ background-color: $dark-color;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 60%;
+ transition: transform 0.2s;
+}
+
+.button:hover {
+ background: $main-accent;
+ cursor: pointer;
+}
+
+.fa-icon-view {
+ margin-left: 3px;
+ margin-top: 5px;
+}
+
+.fa-icon-edit {
+ margin-left: 5px;
+ margin-top: 5px;
+}
+
+.fa-icon-delete {
+ margin-left: 6px;
+ margin-top: 5px;
} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 69df676ff..430c1b694 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -11,6 +11,16 @@ import { ListField } from "../../../fields/ListField";
import { DocumentManager } from "../../util/DocumentManager";
import { LinkEditor } from "./LinkEditor";
import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faEye } from '@fortawesome/free-solid-svg-icons';
+import { faEdit } from '@fortawesome/free-solid-svg-icons';
+import { faTimes } from '@fortawesome/free-solid-svg-icons';
+
+
+library.add(faEye);
+library.add(faEdit);
+library.add(faTimes);
interface Props {
linkDoc: Document;
@@ -79,9 +89,12 @@ export class LinkBox extends React.Component<Props> {
</div>
<div className="button-container">
- <div className="button" onPointerDown={this.onViewButtonPressed}></div>
- <div className="button" onPointerDown={this.onEditButtonPressed}></div>
- <div className="button" onPointerDown={this.onDeleteButtonPressed}></div>
+ <div title="Follow Link" className="button" onPointerDown={this.onViewButtonPressed}>
+ <FontAwesomeIcon className="fa-icon-view" icon="eye" size="sm" /></div>
+ <div title="Edit Link" className="button" onPointerDown={this.onEditButtonPressed}>
+ <FontAwesomeIcon className="fa-icon-edit" icon="edit" size="sm" /></div>
+ <div title="Delete Link" className="button" onPointerDown={this.onDeleteButtonPressed}>
+ <FontAwesomeIcon className="fa-icon-delete" icon="times" size="sm" /></div>
</div>
</div>
)
diff --git a/src/client/views/nodes/LinkEditor.scss b/src/client/views/nodes/LinkEditor.scss
index cb191dc8c..fb0c69cff 100644
--- a/src/client/views/nodes/LinkEditor.scss
+++ b/src/client/views/nodes/LinkEditor.scss
@@ -1,3 +1,4 @@
+@import "../global_variables";
.edit-container {
width: 100%;
height: auto;
@@ -9,21 +10,34 @@
margin-bottom: 10px;
padding: 5px;
font-size: 12px;
+ border: 1px solid #bababa;
}
.description-input {
- font-size: 12px;
+ font-size: 11px;
padding: 5px;
margin-bottom: 10px;
+ border: 1px solid #bababa;
}
.save-button {
width: 50px;
height: 20px;
- background-color: #2B6091;
+ pointer-events: auto;
+ background-color: $dark-color;
+ color: $light-color;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ padding: 2px;
+ font-size: 10px;
margin: 0 auto;
- color: white;
+ transition: transform 0.2s;
text-align: center;
line-height: 20px;
- font-size: 12px;
+}
+
+.save-button:hover {
+ background: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkMenu.scss b/src/client/views/nodes/LinkMenu.scss
index a120ab2a7..dedcce6ef 100644
--- a/src/client/views/nodes/LinkMenu.scss
+++ b/src/client/views/nodes/LinkMenu.scss
@@ -10,6 +10,7 @@
padding: 5px;
margin-bottom: 10px;
font-size: 12px;
+ border: 1px solid #bababa;
}
#linkMenu-list {
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 5c6b06d00..5eeb40772 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -39,8 +39,8 @@ export class LinkMenu extends React.Component<Props> {
<div id="linkMenu-container">
<input id="linkMenu-searchBar" type="text" placeholder="Search..."></input>
<div id="linkMenu-list">
- {this.renderLinkItems(linkTo, KeyStore.LinkedToDocs, "Source: ")}
- {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Destination: ")}
+ {this.renderLinkItems(linkTo, KeyStore.LinkedToDocs, "Destination: ")}
+ {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Source: ")}
</div>
</div>
)
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 9f92410d4..ad947afd5 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -11,5 +11,5 @@
}
.pdfBox-contentContainer {
position: absolute;
- transform-origin: "left top";
+ transform-origin: left top;
} \ No newline at end of file
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 544af41a2..b0b5a63a4 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -86,7 +86,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
@observable private _interactive: boolean = false;
@observable private _loaded: boolean = false;
- @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, 0); }
+ @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); }
componentDidMount() {
this._reactionDisposer = reaction(
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 9c60d4348..8c1ee669f 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -30,7 +30,7 @@ export class VideoBox extends React.Component<FieldViewProps> {
var nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 0);
var nativeHeight = this.props.doc.GetNumber(KeyStore.NativeHeight, 0);
var newNativeHeight = nativeWidth * r.entry.height / r.entry.width;
- if (newNativeHeight != nativeHeight && !isNaN(newNativeHeight)) {
+ if (!nativeHeight && newNativeHeight != nativeHeight && !isNaN(newNativeHeight)) {
this.props.doc.SetNumber(KeyStore.Height, newNativeHeight / nativeWidth * this.props.doc.GetNumber(KeyStore.Width, 0));
this.props.doc.SetNumber(KeyStore.NativeHeight, newNativeHeight);
}
@@ -48,16 +48,14 @@ export class VideoBox extends React.Component<FieldViewProps> {
//setTimeout(action(() => this._loaded = true), 500);
return (
- <div style={{ width: "100%", height: "Auto" }} >
- <Measure onResize={this.setScaling}>
- {({ measureRef }) =>
- <video controls className="videobox-cont" ref={measureRef}>
- <source src={path} type="video/mp4" />
- Not supported.
+ <Measure onResize={this.setScaling}>
+ {({ measureRef }) =>
+ <video className="videobox-cont" ref={measureRef}>
+ <source src={path} type="video/mp4" />
+ Not supported.
</video>
- }
- </Measure>
- </div>
+ }
+ </Measure>
)
}
} \ No newline at end of file
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index 6481e14fe..06cdc8fc8 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -19,11 +19,13 @@ export namespace KeyStore {
export const Annotations = new Key("Annotations");
export const ViewType = new Key("ViewType");
export const Layout = new Key("Layout");
+ export const BackgroundColor = new Key("BackgroundColor");
export const BackgroundLayout = new Key("BackgroundLayout");
export const OverlayLayout = new Key("OverlayLayout");
export const LayoutKeys = new Key("LayoutKeys");
export const LayoutFields = new Key("LayoutFields");
export const ColumnsKey = new Key("SchemaColumns");
+ export const SchemaSplitPercentage = new Key("SchemaSplitPercentage");
export const Caption = new Key("Caption");
export const ActiveFrame = new Key("ActiveFrame");
export const DocumentText = new Key("DocumentText");
@@ -33,7 +35,6 @@ export namespace KeyStore {
export const LinkTags = new Key("LinkTag");
export const Thumbnail = new Key("Thumbnail");
export const CurPage = new Key("CurPage");
- export const CurFrame = new Key("CurFrame");
export const NumPages = new Key("NumPages");
export const Ink = new Key("Ink");
}