From 67a771cbb02ec9da3c60704901f3150b46a7262b Mon Sep 17 00:00:00 2001 From: Georgios Andreadis Date: Wed, 9 Aug 2017 14:29:14 +0300 Subject: Create basic projects page with add-button --- src/components/modals/Modal.js | 82 ++++++++++++++++++++++ src/components/modals/TextInputModal.js | 41 +++++++++++ src/components/navigation/Navbar.js | 6 +- src/components/navigation/Navbar.sass | 4 +- src/components/not-found/BlinkingCursor.js | 8 +++ src/components/not-found/BlinkingCursor.sass | 35 ++++++++++ src/components/not-found/CodeBlock.js | 30 ++++++++ src/components/not-found/CodeBlock.sass | 3 + src/components/not-found/TerminalWindow.js | 26 +++++++ src/components/not-found/TerminalWindow.sass | 70 +++++++++++++++++++ src/components/projects/FilterButton.js | 23 +++++++ src/components/projects/FilterButton.sass | 23 +++++++ src/components/projects/FilterPanel.js | 15 ++++ src/components/projects/FilterPanel.sass | 21 ++++++ src/components/projects/NewProjectButton.js | 16 +++++ src/components/projects/NewProjectButton.sass | 31 +++++++++ src/components/projects/NoProjectsAlert.js | 11 +++ src/components/projects/NoProjectsAlert.sass | 10 +++ src/components/projects/ProjectAuth.js | 22 ++++++ src/components/projects/ProjectAuthList.js | 31 +++++++++ src/components/projects/ProjectAuthList.sass | 98 +++++++++++++++++++++++++++ 21 files changed, 601 insertions(+), 5 deletions(-) create mode 100644 src/components/modals/Modal.js create mode 100644 src/components/modals/TextInputModal.js create mode 100644 src/components/not-found/BlinkingCursor.js create mode 100644 src/components/not-found/BlinkingCursor.sass create mode 100644 src/components/not-found/CodeBlock.js create mode 100644 src/components/not-found/CodeBlock.sass create mode 100644 src/components/not-found/TerminalWindow.js create mode 100644 src/components/not-found/TerminalWindow.sass create mode 100644 src/components/projects/FilterButton.js create mode 100644 src/components/projects/FilterButton.sass create mode 100644 src/components/projects/FilterPanel.js create mode 100644 src/components/projects/FilterPanel.sass create mode 100644 src/components/projects/NewProjectButton.js create mode 100644 src/components/projects/NewProjectButton.sass create mode 100644 src/components/projects/NoProjectsAlert.js create mode 100644 src/components/projects/NoProjectsAlert.sass create mode 100644 src/components/projects/ProjectAuth.js create mode 100644 src/components/projects/ProjectAuthList.js create mode 100644 src/components/projects/ProjectAuthList.sass (limited to 'src/components') diff --git a/src/components/modals/Modal.js b/src/components/modals/Modal.js new file mode 100644 index 00000000..e2d19fcb --- /dev/null +++ b/src/components/modals/Modal.js @@ -0,0 +1,82 @@ +import PropTypes from "prop-types"; +import React from "react"; + +class Modal extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + show: PropTypes.bool.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + }; + static idCounter = 0; + + constructor() { + super(); + this.id = "modal-" + Modal.idCounter; + } + + componentDidMount() { + this.openOrCloseModal(); + } + + componentDidUpdate() { + this.openOrCloseModal(); + } + + onSubmit() { + this.props.onSubmit(); + this.closeModal(); + } + + onCancel() { + this.props.onCancel(); + this.closeModal(); + } + + openModal() { + window["$"]("#" + this.id).modal("show"); + } + + closeModal() { + window["$"]("#" + this.id).modal("hide"); + } + + openOrCloseModal() { + if (this.props.show) { + this.openModal(); + } else { + this.closeModal(); + } + } + + render() { + return ( + + ); + } +} + +export default Modal; diff --git a/src/components/modals/TextInputModal.js b/src/components/modals/TextInputModal.js new file mode 100644 index 00000000..4acf25b3 --- /dev/null +++ b/src/components/modals/TextInputModal.js @@ -0,0 +1,41 @@ +import PropTypes from "prop-types"; +import React from "react"; +import Modal from "./Modal"; + +class TextInputModal extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + show: PropTypes.bool.isRequired, + callback: PropTypes.func.isRequired, + initialValue: PropTypes.string, + }; + + onSubmit() { + this.props.callback(this.refs.textInput.value); + this.refs.textInput.value = ""; + } + + onCancel() { + this.props.callback(undefined); + this.refs.textInput.value = ""; + } + + render() { + return ( + +
+
+ + +
+
+
+ ); + } +} + +export default TextInputModal; diff --git a/src/components/navigation/Navbar.js b/src/components/navigation/Navbar.js index a5f0510f..bd6fd750 100644 --- a/src/components/navigation/Navbar.js +++ b/src/components/navigation/Navbar.js @@ -1,8 +1,8 @@ import React, {Component} from 'react'; +import FontAwesome from "react-fontawesome"; +import Mailto from "react-mailto"; import {Link} from "react-router-dom"; import "./Navbar.css"; -import Mailto from "react-mailto"; -import FontAwesome from "react-fontawesome"; class Navbar extends Component { render() { @@ -19,7 +19,7 @@ class Navbar extends Component {
+ headers={{subject: "OpenDC Support"}}> Profile diff --git a/src/components/navigation/Navbar.sass b/src/components/navigation/Navbar.sass index d40eecfb..a592eab0 100644 --- a/src/components/navigation/Navbar.sass +++ b/src/components/navigation/Navbar.sass @@ -1,5 +1,5 @@ -@import ../../style-globals/mixins.sass -@import ../../style-globals/variables.sass +@import ../../style-globals/_mixins.sass +@import ../../style-globals/_variables.sass .opendc-navbar position: relative diff --git a/src/components/not-found/BlinkingCursor.js b/src/components/not-found/BlinkingCursor.js new file mode 100644 index 00000000..f6c9768c --- /dev/null +++ b/src/components/not-found/BlinkingCursor.js @@ -0,0 +1,8 @@ +import React from "react"; +import "./BlinkingCursor.css"; + +const BlinkingCursor = () => ( + _ +); + +export default BlinkingCursor; diff --git a/src/components/not-found/BlinkingCursor.sass b/src/components/not-found/BlinkingCursor.sass new file mode 100644 index 00000000..6be1476d --- /dev/null +++ b/src/components/not-found/BlinkingCursor.sass @@ -0,0 +1,35 @@ +.blinking-cursor + -webkit-animation: 1s blink step-end infinite + -moz-animation: 1s blink step-end infinite + -o-animation: 1s blink step-end infinite + animation: 1s blink step-end infinite + +@keyframes blink + from, to + color: #eeeeee + 50% + color: #333333 + +@-moz-keyframes blink + from, to + color: #eeeeee + 50% + color: #333333 + +@-webkit-keyframes blink + from, to + color: #eeeeee + 50% + color: #333333 + +@-ms-keyframes blink + from, to + color: #eeeeee + 50% + color: #333333 + +@-o-keyframes blink + from, to + color: #eeeeee + 50% + color: #333333 diff --git a/src/components/not-found/CodeBlock.js b/src/components/not-found/CodeBlock.js new file mode 100644 index 00000000..24d100cc --- /dev/null +++ b/src/components/not-found/CodeBlock.js @@ -0,0 +1,30 @@ +import React from "react"; +import "./CodeBlock.css"; + +const CodeBlock = () => { + const textBlock = + " oo oooo oo
" + + " oo oo oo oo
" + + " oo oo oo oo
" + + " oooooo oo oo oooooo
" + + " oo oo oo oo
" + + " oo oooo oo
"; + const charList = textBlock.split(''); + + // Binary representation of the string "OpenDC!" ;) + const binaryString = "01001111011100000110010101101110010001000100001100100001"; + + let binaryIndex = 0; + for (let i = 0; i < charList.length; i++) { + if (charList[i] === "o") { + charList[i] = binaryString[binaryIndex]; + binaryIndex++; + } + } + + return ( +
+ ); +}; + +export default CodeBlock; diff --git a/src/components/not-found/CodeBlock.sass b/src/components/not-found/CodeBlock.sass new file mode 100644 index 00000000..51a3d3d0 --- /dev/null +++ b/src/components/not-found/CodeBlock.sass @@ -0,0 +1,3 @@ +.code-block + white-space: pre-wrap + margin-top: 60px diff --git a/src/components/not-found/TerminalWindow.js b/src/components/not-found/TerminalWindow.js new file mode 100644 index 00000000..52d3c062 --- /dev/null +++ b/src/components/not-found/TerminalWindow.js @@ -0,0 +1,26 @@ +import React from "react"; +import {Link} from "react-router-dom"; +import BlinkingCursor from "./BlinkingCursor"; +import CodeBlock from "./CodeBlock"; +import "./TerminalWindow.css"; + +const TerminalWindow = () => ( +
+
Terminal -- bash
+
+
$ status
+ opendc[4264]: segfault at 0000051497be459d1 err 12 in libopendc.9.0.4
+ opendc[4269]: segfault at 000004234855fc2db err 3 in libopendc.9.0.4
+ opendc[4270]: STDERR Page does not exist
+
+ +
Got lost?
+ + GET ME BACK TO OPENDC + +
+
+); + + +export default TerminalWindow; diff --git a/src/components/not-found/TerminalWindow.sass b/src/components/not-found/TerminalWindow.sass new file mode 100644 index 00000000..4f51a77f --- /dev/null +++ b/src/components/not-found/TerminalWindow.sass @@ -0,0 +1,70 @@ +.terminal-window + width: 600px + height: 400px + display: block + + position: absolute + top: 0 + bottom: 0 + left: 0 + right: 0 + + margin: auto + + -webkit-user-select: none + -moz-user-select: none + -ms-user-select: none + user-select: none + cursor: default + + overflow: hidden + + box-shadow: 5px 5px 20px #444444 + +.terminal-header + font-family: monospace + background: #cccccc + color: #444444 + height: 30px + line-height: 30px + padding-left: 10px + + border-top-left-radius: 7px + border-top-right-radius: 7px + +.terminal-body + font-family: monospace + text-align: center + background-color: #333333 + color: #eeeeee + padding: 10px + + height: 100% + +.segfault + text-align: left + +.sub-title + margin-top: 20px + +.home-btn + margin-top: 10px + padding: 5px + display: inline-block + border: 1px solid #eeeeee + color: #eeeeee + text-decoration: none + cursor: pointer + + -webkit-transition: all 200ms + -moz-transition: all 200ms + -o-transition: all 200ms + transition: all 200ms + +.home-btn:hover + background: #eeeeee + color: #333333 + +.home-btn:active + background: #333333 + color: #eeeeee diff --git a/src/components/projects/FilterButton.js b/src/components/projects/FilterButton.js new file mode 100644 index 00000000..8d6b7146 --- /dev/null +++ b/src/components/projects/FilterButton.js @@ -0,0 +1,23 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; +import "./FilterButton.css"; + +const FilterButton = ({active, children, onClick}) => ( +
{ + if (!active) { + onClick(); + } + }}> + {children} +
+); + +FilterButton.propTypes = { + active: PropTypes.bool.isRequired, + children: PropTypes.node.isRequired, + onClick: PropTypes.func.isRequired +}; + +export default FilterButton; diff --git a/src/components/projects/FilterButton.sass b/src/components/projects/FilterButton.sass new file mode 100644 index 00000000..0cad68e3 --- /dev/null +++ b/src/components/projects/FilterButton.sass @@ -0,0 +1,23 @@ +@import ../../style-globals/_mixins.sass +@import ../../style-globals/_variables.sass + +.project-filter-button + display: inline-block + width: 33.3% + //margin-right: -4px + padding: 10px $global-padding + + font-size: 12pt + border-right: 1px solid #06326b + + +clickable + +transition(background, $transition-length) + +.project-filter-button:last-of-type + border: 0 + +.project-filter-button:hover + background: #0c60bf + +.project-filter-button:active, .project-filter-button.active + background: #073d7d diff --git a/src/components/projects/FilterPanel.js b/src/components/projects/FilterPanel.js new file mode 100644 index 00000000..050bf0aa --- /dev/null +++ b/src/components/projects/FilterPanel.js @@ -0,0 +1,15 @@ +import React from 'react'; +import FilterLink from "../../containers/projects/FilterLink"; +import "./FilterPanel.css"; + +const ProjectFilterPanel = () => ( +
+
+ All Projects + My Projects + Projects shared with me +
+
+); + +export default ProjectFilterPanel; diff --git a/src/components/projects/FilterPanel.sass b/src/components/projects/FilterPanel.sass new file mode 100644 index 00000000..a70c7a90 --- /dev/null +++ b/src/components/projects/FilterPanel.sass @@ -0,0 +1,21 @@ +@import ../../style-globals/_mixins.sass +@import ../../style-globals/_variables.sass + +.filter-menu + display: block + + background: #0761b1 + border: 1px solid #06326b + color: #eee + + text-align: center + + +border-radius($standard-border-radius) + overflow: hidden + + margin-bottom: 20px + + .project-filters + display: block + overflow: hidden + margin: 0 -1px diff --git a/src/components/projects/NewProjectButton.js b/src/components/projects/NewProjectButton.js new file mode 100644 index 00000000..9eaf6df4 --- /dev/null +++ b/src/components/projects/NewProjectButton.js @@ -0,0 +1,16 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import './NewProjectButton.css'; + +const NewProjectButton = ({onClick}) => ( +
+ + New Project +
+); + +NewProjectButton.propTypes = { + onClick: PropTypes.func.isRequired, +}; + +export default NewProjectButton; diff --git a/src/components/projects/NewProjectButton.sass b/src/components/projects/NewProjectButton.sass new file mode 100644 index 00000000..89435902 --- /dev/null +++ b/src/components/projects/NewProjectButton.sass @@ -0,0 +1,31 @@ +@import ../../style-globals/_mixins.sass +@import ../../style-globals/_variables.sass + +.new-project-btn + $button-height: 35px + + display: inline-block + position: absolute + bottom: $navbar-height + 40px + right: 40px + padding: 0 10px + height: $button-height + line-height: $button-height + font-size: 14pt + + background: #679436 + color: #eee + border: 1px solid #507830 + + +border-radius($standard-border-radius) + +clickable + +transition(all, $transition-length) + + span + margin-right: 10px + +.new-project-btn:hover + background: #73ac45 + +.new-project-btn:active + background: #5c8835 diff --git a/src/components/projects/NoProjectsAlert.js b/src/components/projects/NoProjectsAlert.js new file mode 100644 index 00000000..957435c7 --- /dev/null +++ b/src/components/projects/NoProjectsAlert.js @@ -0,0 +1,11 @@ +import React from 'react'; +import "./NoProjectsAlert.css"; + +const NoProjectsAlert = () => ( +
+ + No projects here yet... Add some with the 'New Project' button! +
+); + +export default NoProjectsAlert; diff --git a/src/components/projects/NoProjectsAlert.sass b/src/components/projects/NoProjectsAlert.sass new file mode 100644 index 00000000..a526f9ad --- /dev/null +++ b/src/components/projects/NoProjectsAlert.sass @@ -0,0 +1,10 @@ +.no-projects-alert + position: relative + padding-left: 50px + + .info-icon + position: absolute + top: 11px + left: 15px + bottom: 10px + font-size: 20pt diff --git a/src/components/projects/ProjectAuth.js b/src/components/projects/ProjectAuth.js new file mode 100644 index 00000000..7e3abae1 --- /dev/null +++ b/src/components/projects/ProjectAuth.js @@ -0,0 +1,22 @@ +import classNames from 'classnames'; +import React from 'react'; +import Shapes from "../../shapes/index"; +import {AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP} from "../../util/authorizations"; +import {parseAndFormatDateTime} from "../../util/date-time"; + +const ProjectAuth = ({projectAuth}) => ( +
+
{projectAuth.simulation.name}
+
{parseAndFormatDateTime(projectAuth.simulation.datetimeLastEdited)}
+
+ + {AUTH_DESCRIPTION_MAP[projectAuth.authorizationLevel]} +
+
+); + +ProjectAuth.propTypes = { + projectAuth: Shapes.Authorization.isRequired, +}; + +export default ProjectAuth; diff --git a/src/components/projects/ProjectAuthList.js b/src/components/projects/ProjectAuthList.js new file mode 100644 index 00000000..093b3279 --- /dev/null +++ b/src/components/projects/ProjectAuthList.js @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import Shapes from "../../shapes/index"; +import NoProjectsAlert from "./NoProjectsAlert"; +import ProjectAuth from "./ProjectAuth"; +import "./ProjectAuthList.css"; + +const ProjectAuthList = ({authorizations, onProjectClick}) => ( +
+
+
Project name
+
Last edited
+
Access rights
+
+
+ {authorizations.length === 0 ? + : + authorizations.map(authorization => ( + + )) + } +
+
+); + +ProjectAuthList.propTypes = { + authorizations: PropTypes.arrayOf(Shapes.Authorization).isRequired, + onProjectClick: PropTypes.func.isRequired, +}; + +export default ProjectAuthList; diff --git a/src/components/projects/ProjectAuthList.sass b/src/components/projects/ProjectAuthList.sass new file mode 100644 index 00000000..86e1123c --- /dev/null +++ b/src/components/projects/ProjectAuthList.sass @@ -0,0 +1,98 @@ +@import ../../style-globals/_mixins.sass +@import ../../style-globals/_variables.sass + +.project-list + display: block + font-size: 12pt + border: 0 + + .list-head, .list-body .project-row + display: block + position: relative + + .list-head div, .list-body .project-row div + padding: 0 10px + display: inline-block + + .list-head + font-weight: bold + + // Address default margin between inline-blocks + div + margin-right: -4px + +.project-row + background: #f8f8f8 + border: 1px solid #b6b6b6 + height: 40px + line-height: 40px + clear: both + + +transition(background, $transition-length) + +clickable + +.project-row:hover + background: #fff + +.project-row:active + background: #cccccc + +.project-row:not(:first-of-type) + margin-top: -1px + +// Sizing of table columns +.project-row, .project-list .list-head + div:first-of-type + width: 50% + + div:nth-of-type(2) + width: 30% + + div:last-of-type + width: 20% + + span + margin-right: 10px + +.project-row.active + border-bottom: 0 + background: #3442b1 + color: #eee + +.project-view + padding: 10px + overflow: hidden + border: 1px solid #b6b6b6 + border-top: 0 + + background: #3442b1 + color: #eee + + .participants + display: inline-block + float: left + + .access-buttons + display: inline-block + float: right + + .inline-btn + margin-left: 10px + + .open + background: #e38829 + + .open:hover + background: #ff992e + + .open:active + background: #ba6f21 + + .edit + background: #2c3897 + + .edit:hover + background: #3a4ac8 + + .edit:active + background: #242d7a -- cgit v1.2.3