aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Eichmann <philipp.eichmann@gmail.com>2018-12-21 18:45:24 -0500
committerPhilipp Eichmann <philipp.eichmann@gmail.com>2018-12-21 18:45:24 -0500
commit06098b7bdd6a83f6b9cc07d2377f2a19cc0ecaa6 (patch)
treed665964243f9949424555175711e27166e96f70e /src
parent9caa9ca4a0b413e2da03eff4856cb324939d77d4 (diff)
added code
Diffstat (limited to 'src')
-rw-r--r--src/Main.scss25
-rw-r--r--src/Main.tsx32
-rw-r--r--src/Utils.ts11
-rw-r--r--src/stores/NodeCollectionStore.ts21
-rw-r--r--src/stores/NodeStore.ts24
-rw-r--r--src/stores/RootStore.ts16
-rw-r--r--src/stores/StaticTextNodeStore.ts16
-rw-r--r--src/stores/VideoNodeStore.ts17
-rw-r--r--src/views/freeformcanvas/FreeFormCanvas.scss15
-rw-r--r--src/views/freeformcanvas/FreeFormCanvas.tsx54
-rw-r--r--src/views/freeformcanvas/NodeContainer.tsx30
-rw-r--r--src/views/nodes/NodeView.scss33
-rw-r--r--src/views/nodes/TextNodeView.tsx28
-rw-r--r--src/views/nodes/TopBar.tsx46
-rw-r--r--src/views/nodes/VideoNodeView.scss5
-rw-r--r--src/views/nodes/VideoNodeView.tsx29
16 files changed, 402 insertions, 0 deletions
diff --git a/src/Main.scss b/src/Main.scss
new file mode 100644
index 000000000..f986d2c96
--- /dev/null
+++ b/src/Main.scss
@@ -0,0 +1,25 @@
+html,
+body {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ font-family: 'Hind Siliguri', sans-serif;
+}
+
+h1 {
+ font-size: 50px;
+ position: fixed;
+ top: 30px;
+ left: 50%;
+ transform: translateX(-50%);
+ color: black;
+ 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;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+} \ No newline at end of file
diff --git a/src/Main.tsx b/src/Main.tsx
new file mode 100644
index 000000000..99401bf65
--- /dev/null
+++ b/src/Main.tsx
@@ -0,0 +1,32 @@
+import * as React from 'react';
+import * as ReactDOM from 'react-dom';
+import "./Main.scss";
+import { NodeCollectionStore } from './stores/NodeCollectionStore';
+import { RootStore } from './stores/RootStore';
+import { StaticTextNodeStore } from './stores/StaticTextNodeStore';
+import { VideoNodeStore } from './stores/VideoNodeStore';
+import { FreeFormCanvas } from './views/freeformcanvas/FreeFormCanvas';
+
+
+const mainNodeCollection = new NodeCollectionStore();
+ReactDOM.render((
+ <div>
+ <h1>Dash Web</h1>
+ <FreeFormCanvas store={mainNodeCollection} />
+ </div>), document.getElementById('root'));
+
+
+
+// create a bunch of text and video nodes (you probably want to delete this at some point)
+let numNodes = 300;
+let maxX = 10000;
+let maxY = 10000;
+let nodes = []
+for (let i = 0; i < numNodes; i++) {
+ nodes.push(new StaticTextNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Text Node Title", Text: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?" }));
+}
+
+for (let i = 0; i < 20; i++) {
+ nodes.push(new VideoNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Video Node Title", Url: "http://cs.brown.edu/people/peichman/downloads/cted.mp4" }));
+}
+mainNodeCollection.AddNodes(nodes); \ No newline at end of file
diff --git a/src/Utils.ts b/src/Utils.ts
new file mode 100644
index 000000000..7f26bc394
--- /dev/null
+++ b/src/Utils.ts
@@ -0,0 +1,11 @@
+
+
+export class Utils {
+
+ public static GenerateGuid() {
+ function s4() {
+ return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
+ }
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
+ }
+} \ No newline at end of file
diff --git a/src/stores/NodeCollectionStore.ts b/src/stores/NodeCollectionStore.ts
new file mode 100644
index 000000000..8c7f7623b
--- /dev/null
+++ b/src/stores/NodeCollectionStore.ts
@@ -0,0 +1,21 @@
+import { computed, observable, action } from "mobx";
+import { NodeStore } from "./NodeStore";
+
+export class NodeCollectionStore extends NodeStore {
+
+ @observable
+ public Scale: number = 1;
+
+ @observable
+ public Nodes: NodeStore[] = new Array<NodeStore>();
+
+ @computed
+ public get Transform(): string {
+ return "translate(" + this.X + "px," + this.Y + "px) scale(" + this.Scale + "," + this.Scale + ")";
+ }
+
+ @action
+ public AddNodes(stores: NodeStore[]): void {
+ stores.forEach(store => this.Nodes.push(store));
+ }
+} \ No newline at end of file
diff --git a/src/stores/NodeStore.ts b/src/stores/NodeStore.ts
new file mode 100644
index 000000000..6a734cf44
--- /dev/null
+++ b/src/stores/NodeStore.ts
@@ -0,0 +1,24 @@
+import { computed, observable } from "mobx";
+import { Utils } from "../Utils";
+
+export class NodeStore {
+
+ public Id: string = Utils.GenerateGuid();
+
+ @observable
+ public X: number = 0;
+
+ @observable
+ public Y: number = 0;
+
+ @observable
+ public Width: number = 0;
+
+ @observable
+ public Height: number = 0;
+
+ @computed
+ public get Transform(): string {
+ return "translate(" + this.X + "px, " + this.Y + "px)";
+ }
+} \ No newline at end of file
diff --git a/src/stores/RootStore.ts b/src/stores/RootStore.ts
new file mode 100644
index 000000000..fa551c1d1
--- /dev/null
+++ b/src/stores/RootStore.ts
@@ -0,0 +1,16 @@
+import { action, observable } from "mobx";
+import { NodeStore } from "./NodeStore";
+
+// This globally accessible store might come in handy, although you may decide that you don't need it.
+export class RootStore {
+
+ private constructor() {
+ // initialization code
+ }
+
+ private static _instance: RootStore;
+
+ public static get Instance():RootStore {
+ return this._instance || (this._instance = new this());
+ }
+} \ No newline at end of file
diff --git a/src/stores/StaticTextNodeStore.ts b/src/stores/StaticTextNodeStore.ts
new file mode 100644
index 000000000..7c342a7a2
--- /dev/null
+++ b/src/stores/StaticTextNodeStore.ts
@@ -0,0 +1,16 @@
+import { observable } from "mobx";
+import { NodeStore } from "./NodeStore";
+
+export class StaticTextNodeStore extends NodeStore {
+
+ constructor(initializer: Partial<StaticTextNodeStore>) {
+ super();
+ Object.assign(this, initializer);
+ }
+
+ @observable
+ public Title: string = "";
+
+ @observable
+ public Text: string = "";
+} \ No newline at end of file
diff --git a/src/stores/VideoNodeStore.ts b/src/stores/VideoNodeStore.ts
new file mode 100644
index 000000000..41fae2aff
--- /dev/null
+++ b/src/stores/VideoNodeStore.ts
@@ -0,0 +1,17 @@
+import { observable } from "mobx";
+import { NodeStore } from "./NodeStore";
+
+export class VideoNodeStore extends NodeStore {
+
+ constructor(initializer: Partial<VideoNodeStore>) {
+ super();
+ Object.assign(this, initializer);
+ }
+
+ @observable
+ public Title: string;
+
+ @observable
+ public Url: string;
+
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/FreeFormCanvas.scss b/src/views/freeformcanvas/FreeFormCanvas.scss
new file mode 100644
index 000000000..884ef90e6
--- /dev/null
+++ b/src/views/freeformcanvas/FreeFormCanvas.scss
@@ -0,0 +1,15 @@
+.freeformcanvas-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+
+ .freeformcanvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+}
+
diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx
new file mode 100644
index 000000000..f02f677a3
--- /dev/null
+++ b/src/views/freeformcanvas/FreeFormCanvas.tsx
@@ -0,0 +1,54 @@
+import { observer } from "mobx-react";
+import { NodeCollectionStore } from "../../stores/NodeCollectionStore";
+import "./FreeFormCanvas.scss";
+import { NodeContainer } from "./NodeContainer";
+import React = require("react");
+
+interface IProps {
+ store: NodeCollectionStore
+}
+
+@observer
+export class FreeFormCanvas extends React.Component<IProps> {
+
+ private _isPointerDown: boolean;
+
+ onPointerDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._isPointerDown = true;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+
+ onPointerUp = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._isPointerDown = false;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ onPointerMove = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ if (!this._isPointerDown) {
+ return;
+ }
+ this.props.store.X += e.movementX;
+ this.props.store.Y += e.movementY;
+ }
+
+ render() {
+ let store = this.props.store;
+ return (
+ <div className="freeformcanvas-container" onPointerDown={this.onPointerDown}>
+ <div className="freeformcanvas" style={{ transform: store.Transform }}>
+ <NodeContainer store={store} />
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/NodeContainer.tsx b/src/views/freeformcanvas/NodeContainer.tsx
new file mode 100644
index 000000000..a2edb38a4
--- /dev/null
+++ b/src/views/freeformcanvas/NodeContainer.tsx
@@ -0,0 +1,30 @@
+import { observer } from "mobx-react";
+import { NodeCollectionStore } from "../../stores/NodeCollectionStore";
+import { StaticTextNodeStore } from "../../stores/StaticTextNodeStore";
+import { VideoNodeStore } from "../../stores/VideoNodeStore";
+import { TextNodeView } from "../nodes/TextNodeView";
+import { VideoNodeView } from "../nodes/VideoNodeView";
+import "./FreeFormCanvas.scss";
+import React = require("react");
+
+interface IProps {
+ store: NodeCollectionStore
+}
+
+@observer
+export class NodeContainer extends React.Component<IProps> {
+
+ render() {
+ return (
+ <div className="node-container">
+ {this.props.store.Nodes.map(nodeStore => {
+ if (nodeStore instanceof StaticTextNodeStore) {
+ return (<TextNodeView key={nodeStore.Id} store={nodeStore as StaticTextNodeStore} />)
+ } else if (nodeStore instanceof VideoNodeStore) {
+ return (<VideoNodeView key={nodeStore.Id} store={nodeStore as VideoNodeStore} />)
+ }
+ })}
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/views/nodes/NodeView.scss b/src/views/nodes/NodeView.scss
new file mode 100644
index 000000000..2dfdee6fa
--- /dev/null
+++ b/src/views/nodes/NodeView.scss
@@ -0,0 +1,33 @@
+.node {
+ position: absolute;
+ background: #cdcdcd;
+
+ width: 300px;
+ height: 300px;
+ 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/views/nodes/TextNodeView.tsx b/src/views/nodes/TextNodeView.tsx
new file mode 100644
index 000000000..4831e658c
--- /dev/null
+++ b/src/views/nodes/TextNodeView.tsx
@@ -0,0 +1,28 @@
+import { observer } from "mobx-react";
+import { StaticTextNodeStore } from "../../stores/StaticTextNodeStore";
+import "./NodeView.scss";
+import { TopBar } from "./TopBar";
+import React = require("react");
+
+interface IProps {
+ store: StaticTextNodeStore;
+}
+
+@observer
+export class TextNodeView extends React.Component<IProps> {
+
+ render() {
+ let store = this.props.store;
+ return (
+ <div className="node text-node" style={{ transform: store.Transform }}>
+ <TopBar store={store} />
+ <div className="scroll-box">
+ <div className="content">
+ <h3 className="title">{store.Title}</h3>
+ <p className="paragraph">{store.Text}</p>
+ </div>
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/views/nodes/TopBar.tsx b/src/views/nodes/TopBar.tsx
new file mode 100644
index 000000000..bb126e8b5
--- /dev/null
+++ b/src/views/nodes/TopBar.tsx
@@ -0,0 +1,46 @@
+import { observer } from "mobx-react";
+import { NodeStore } from "../../stores/NodeStore";
+import "./NodeView.scss";
+import React = require("react");
+
+interface IProps {
+ store: NodeStore;
+}
+
+@observer
+export class TopBar extends React.Component<IProps> {
+
+ private _isPointerDown = false;
+
+ onPointerDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._isPointerDown = true;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+
+ onPointerUp = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._isPointerDown = false;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ onPointerMove = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ if (!this._isPointerDown) {
+ return;
+ }
+ this.props.store.X += e.movementX;
+ this.props.store.Y += e.movementY;
+ }
+
+ render() {
+ return <div className="top" onPointerDown={this.onPointerDown}></div>
+ }
+}
diff --git a/src/views/nodes/VideoNodeView.scss b/src/views/nodes/VideoNodeView.scss
new file mode 100644
index 000000000..f412c3519
--- /dev/null
+++ b/src/views/nodes/VideoNodeView.scss
@@ -0,0 +1,5 @@
+.node {
+ video {
+ width: 100%;
+ }
+} \ No newline at end of file
diff --git a/src/views/nodes/VideoNodeView.tsx b/src/views/nodes/VideoNodeView.tsx
new file mode 100644
index 000000000..0a7b3d174
--- /dev/null
+++ b/src/views/nodes/VideoNodeView.tsx
@@ -0,0 +1,29 @@
+import { observer } from "mobx-react";
+import { VideoNodeStore } from "../../stores/VideoNodeStore";
+import "./NodeView.scss";
+import { TopBar } from "./TopBar";
+import "./VideoNodeView.scss";
+import React = require("react");
+
+interface IProps {
+ store: VideoNodeStore;
+}
+
+@observer
+export class VideoNodeView extends React.Component<IProps> {
+
+ render() {
+ let store = this.props.store;
+ return (
+ <div className="node text-node" style={{ transform: store.Transform }}>
+ <TopBar store={store} />
+ <div className="scroll-box">
+ <div className="content">
+ <h3 className="title">{store.Title}</h3>
+ <video src={store.Url} controls />
+ </div>
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file