diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 109b5e2..9425ee9 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -10,7 +10,6 @@ var getClientEnvironment = require('./env'); var paths = require('./paths'); - // Webpack uses `publicPath` to determine where the app is being served from. // In development, we always serve from the root. This makes config easier. var publicPath = '/'; @@ -75,10 +74,11 @@ module.exports = { // some tools, although we do not recommend using it, see: // https://github.com/facebookincubator/create-react-app/issues/290 extensions: ['.js', '.json', '.jsx', ''], + modulesDirectories: [ 'src-react', 'node_modules' ], alias: { // Support React Native Web // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ - 'react-native': 'react-native-web' + 'react-native': 'react-native-web', } }, @@ -111,6 +111,7 @@ module.exports = { // Webpack 2 fixes this, but for now we include this hack. // https://github.com/facebookincubator/create-react-app/issues/1713 /\.(js|jsx)(\?.*)?$/, + /\.scss$/, /\.css$/, /\.json$/, /\.svg$/ @@ -143,6 +144,10 @@ module.exports = { test: /\.css$/, loader: 'style!css?importLoaders=1!postcss' }, + { + test: /\.scss$/, + loader: 'style!css!sass' + }, // JSON is not enabled by default in Webpack but both Node and Browserify // allow it implicitly so we also enable it. { diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 74a54b6..54398da 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -79,10 +79,11 @@ module.exports = { // some tools, although we do not recommend using it, see: // https://github.com/facebookincubator/create-react-app/issues/290 extensions: ['.js', '.json', '.jsx', ''], + modulesDirectories: [ 'src-react', 'node_modules' ], alias: { // Support React Native Web // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ - 'react-native': 'react-native-web' + 'react-native': 'react-native-web', } }, diff --git a/package.json b/package.json index 0443646..8b439c2 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "bluebird": "~3.5.0", "blueimp-md5": "~2.7.0", "body-parser": "~1.17.1", + "bootstrap-sass": "^3.3.7", "color": "~1.0.3", "cookie-parser": "~1.4.3", "crossroads": "~0.12.2", @@ -55,6 +56,10 @@ "passport-local": "~1.0.0", "raven": "~1.2.1", "rc": "~1.2.1", + "react": "^15.5.4", + "react-dom": "^15.5.4", + "react-redux": "^5.0.4", + "redux": "^3.6.0", "rimraf": "~2.6.1", "semver": "~5.3.0", "serve-static": "~1.12.2", @@ -64,11 +69,7 @@ "superagent": "^0.21.0", "temp": "~0.8.3", "winston": "~2.3.1", - "yargs": "~8.0.0-candidate.0", - "react": "^15.5.4", - "react-dom": "^15.5.4", - "react-redux": "^5.0.4", - "redux": "^3.6.0" + "yargs": "~8.0.0-candidate.0" }, "devDependencies": { "ansi-color": "~0.2.1", @@ -122,11 +123,13 @@ "jest": "18.1.0", "json-loader": "0.5.4", "mocha": "~3.3.0", + "node-sass": "^4.5.3", "object-assign": "4.1.1", "phantomjs-prebuilt": "~2.1.14", "postcss-loader": "1.2.2", "promise": "7.1.1", "react-dev-utils": "^0.5.2", + "sass-loader": "^6.0.5", "style-loader": "0.13.1", "supertest": "~3.0.0", "url-loader": "0.5.7", diff --git a/src-react/containers/path.js b/src-react/containers/path.js index cb2c1b0..499d4e9 100644 --- a/src-react/containers/path.js +++ b/src-react/containers/path.js @@ -1,6 +1,8 @@ import React, { Component } from 'react'; import { connect } from 'react-redux' +import 'styles/styles.scss'; + @connect(state => { return { ...state } }) class Path extends Component { render() { diff --git a/src-react/styles/d2h.scss b/src-react/styles/d2h.scss new file mode 100644 index 0000000..199347a --- /dev/null +++ b/src-react/styles/d2h.scss @@ -0,0 +1,206 @@ +/* +* +* Diff to HTML (diff2html.css) +* Author: rtfpessoa +* Modified by: codingtwinky +* Date: Friday 29 August 2014 +* Last Update: Saturday 27 September 2014 +* +*/ + +.d2h-wrapper { + display: block; + margin: 0 auto; + text-align: left; + width: 100%; +} + +.d2h-file-wrapper { + border-radius: 3px; +} + +.d2h-file-header { + display: none; +} + +.d2h-file-stats { + display: inline; + font-size: 12px; + text-align: center; + max-width: 15%; +} + +.d2h-lines-added { + background-color: #ceffce; + border: 1px solid #b4e2b4; + color: #FFFFFF; + border-radius: 5px 0 0 5px; + padding: 2px; + width: 25px; +} + +.d2h-lines-deleted { + background-color: #f7c8c8; + border: 1px solid #e9aeae; + color: #000000; + border-radius: 0 5px 5px 0; + padding: 2px; + width: 25px; +} + +.d2h-file-name { + display: inline; + height: 33px; + max-width: 80%; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.d2h-diff-table { + border-collapse: collapse; + font-family: 'Source Code Pro'; + font-size: 12px; + height: 19px; + width: 100%; + tbody > tr > td { + padding: 0px; + border-spacing: 0px; + height: 105%; + } +} + +.d2h-files-diff { + width: 100%; + display: flex; +} + +.d2h-file-diff { + overflow-x: auto; + overflow-y: hidden; +} + +.d2h-file-side-diff { + display: inline-block; + overflow-x: auto; + width: 50%; +} + +.d2h-code-line { + white-space: pre; + padding-left: 10px; + padding-right: 10px; + display: inline-flex; +} + +.d2h-code-side-line { + white-space: pre; + padding-left: 5px; + padding-right: 5px; + display: inline-flex; +} + +.d2h-code-line del, +.d2h-code-side-line del { + display: inline-block; + margin-top: -1px; + text-decoration: none; + background-color: rgba(255, 255, 255, 0.2); +} + +.d2h-code-line ins, +.d2h-code-side-line ins { + display: inline-block; + margin-top: -1px; + text-decoration: none; + background-color: rgba(255, 255, 255, 0.6); +} + +.d2h-code-line-prefix { + display: inline-flex; + margin-right: 10px; +} + +.line-num1 { + display: inline-block; + float: left; + width: 30px; + overflow: hidden; + text-overflow: ellipsis; +} + +.line-num2 { + display: inline-block; + float: right; + width: 30px; + overflow: hidden; + text-overflow: ellipsis; +} + +.d2h-code-linenumber { + position: static; + width: 52px; + min-width: 65px; + text-align: center; + background-color: #727a83; + color: rgba(0, 0, 0, 0.5); + border-width: 0 1px 0 1px; + cursor: pointer; + overflow: hidden; + text-overflow: ellipsis; + border-left: 1px solid rgba(0, 0, 0, 0.34); + border-right: 1px solid rgba(0, 0, 0, 0.34); +} + +.d2h-cntx { + color: rgba(255, 255, 255, 0.3); +} + +.d2h-code-side-linenumber { + position: static; + display: table-cell; + width: 52px; + min-width: 65px; + text-align: center; + height: 100%; + background-color: rgba(114, 122, 131, 1); + color: rgba(0, 0, 0, 0.5); + border-width: 0 1px 0 1px; + cursor: pointer; + overflow: hidden; + text-overflow: ellipsis; + border-left: 1px solid rgba(0, 0, 0, 0.34); + border-right: 1px solid rgba(0, 0, 0, 0.34); +} + +.d2h-del { + background-color: #E86756; + color: #FFFFFF; + + &.d2h-code-side-linenumber { + color: rgba(0, 0, 0, 0.5); + } +} + +.d2h-ins { + background-color: #66F27B; + color: #000000; + + &.d2h-code-side-linenumber { + color: rgba(0, 0, 0, 0.5); + } +} + +.d2h-info { + color: rgba(255, 255, 255, 0.3); +} + +.d2h-code-line-ctn { + .word-wrap & { + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -webkit-pre-wrap; /*Chrome & Safari */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* css-3 */ + } +} diff --git a/src-react/styles/fonts/OpenSans.woff b/src-react/styles/fonts/OpenSans.woff new file mode 100644 index 0000000..55b25f8 Binary files /dev/null and b/src-react/styles/fonts/OpenSans.woff differ diff --git a/src-react/styles/fonts/SourceCodePro-Medium.woff b/src-react/styles/fonts/SourceCodePro-Medium.woff new file mode 100644 index 0000000..653d5dd Binary files /dev/null and b/src-react/styles/fonts/SourceCodePro-Medium.woff differ diff --git a/src-react/styles/generic.scss b/src-react/styles/generic.scss new file mode 100644 index 0000000..0c30894 --- /dev/null +++ b/src-react/styles/generic.scss @@ -0,0 +1,194 @@ + +// Generic.less +// This file can be used to style any page to look like "ungit", i.e. anything that's not +// application specific goes here. + +@import "variables.scss"; +@import "~bootstrap-sass/assets/stylesheets/_bootstrap-mincer.scss"; +@import "~bootstrap-sass/assets/stylesheets/_bootstrap.scss"; +@import "~octicons/octicons/octicons.css"; + +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url('./fonts/OpenSans.woff') format('woff'); +} + +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: local('Source Code Pro Medium'), local('SourceCodePro-Medium'), url('./fonts/SourceCodePro-Medium.woff') format('woff'); +} + +// -- Bootstrap styling --- + +.btn { + .glyphicon { + font-size: 0.8em; + margin-right: 0.1em; + } + &:focus { + outline: none; + } +} + +.btn, .list-group-item { + position: relative; + & > .progress { + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + background: transparent; + pointer-events:none; + .progress-bar { + pointer-events:none; + } + } +} +.btn-group { + .btn > .progress { + border-radius: 0px; + .progress-bar { + border-radius: 0px; + } + } +} + +.panel { + border: 0px; +} + +.form-control { + border: 0px; + color: rgba(255, 255, 255, 0.8); +} + +.list-group-item { + background: rgba(0, 0, 0, 0.09); + border: 0px; + margin-bottom: 3px; +} +div.list-group-item { + &:hover { + background: $list-group-hover-bg; + } + a:hover { + text-decoration: none; + } +} + +// -- New generic classes ---- + +.container.container-wide { + width: 100%; + padding-left: 40px; + padding-right: 40px; +} + +hr { + border: 0px; + border-top: 1px solid rgba(255, 255, 255, 0.1); + background: transparent; + height: 0px; +} + +a.disabled { + pointer-events: none; + opacity: 0.5; +} + +.list-group-item .list-item-remove { + position: absolute; + right: 0px; + top: 0px; + background: transparent; + border: 0px; + opacity: 0.3; + &:hover { + opacity: 1; + } +} + +.arrowContainer { + position: relative; + &.arrowRight .arrow, + &.arrowRight .shadow, + &.arrowLeft .arrow, + &.arrowLeft .shadow { + width: 15px; + height: 30px; + margin-top: 22px; + } + &.arrowUp .arrow, + &.arrowUp .shadow, + &.arrowDown .arrow, + &.arrowDown .shadow { + width: 30px; + height: 15px; + } + .shadow { + position: absolute; + left: 5px; + top: 5px; + } + .arrow { + position: absolute; + left: 0px; + top: 0px; + } +} + +.droparea { + position: relative; + border-radius: 3px; + padding: 0.3em; + display: inline-block; + background: #2B4C5C; + padding: 5px; + padding-left: 10px; + padding-right: 10px; + .dropmask { + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + } + .progress { + position: absolute; + width: 100%; + height: 100%; + left: 0px; + top: 0px; + background: transparent; + } +} + + +.text-dimmed { + opacity: 0.6; +} + +::-webkit-scrollbar { + width: 15px; +} +::-webkit-scrollbar-track { + background-color: #2B3844; +} +::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); +} +::-webkit-scrollbar-button { + background-color: rgba(0, 0, 0, 0.2); +} +::-webkit-scrollbar-corner { + background-color: black; +} + +.create-dir { + margin-top: 50px; +} diff --git a/src-react/styles/images/branchIcon.svg b/src-react/styles/images/branchIcon.svg new file mode 100644 index 0000000..8a3c760 --- /dev/null +++ b/src-react/styles/images/branchIcon.svg @@ -0,0 +1,103 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src-react/styles/images/remoteIcon.svg b/src-react/styles/images/remoteIcon.svg new file mode 100644 index 0000000..269c91d --- /dev/null +++ b/src-react/styles/images/remoteIcon.svg @@ -0,0 +1,65 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src-react/styles/images/tagIcon.svg b/src-react/styles/images/tagIcon.svg new file mode 100644 index 0000000..36b6d00 --- /dev/null +++ b/src-react/styles/images/tagIcon.svg @@ -0,0 +1,64 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src-react/styles/styles.scss b/src-react/styles/styles.scss new file mode 100644 index 0000000..42abdf9 --- /dev/null +++ b/src-react/styles/styles.scss @@ -0,0 +1,119 @@ +// Styles.less +// This file contains styling that's only used in this app + +@import "generic.scss"; + + +// -- Application specific layout ---- +// Needed to properly layout this specific page regardless of the specific bootstrap configuration/styling + +.glyphicon-circled { + margin-right: 18px; + border: 5px solid #686868; + border-radius: 100%; + padding-bottom: 7px; + padding-top: 6px; + padding-right: 20px; + padding-left: 7px; +} + +.repository-actions { + position: absolute; + margin-top: 20px; + right: 0px; + z-index: 30; +} + +.crash { + margin-top: 20px; +} + +// -- Application specific styling ---- +.btn-load-more { + padding-top: 10px; + padding-bottom: 10px; + .btn { + margin-right: auto; + margin-left: auto; + display: table; + } +} + +.ui-autocomplete { + background: rgba(200, 210, 230, 1); + box-shadow: 13px 13px 0px rgba(0, 0, 0, 0.2); + border-radius: 5px; + margin-top: 3px; + position: absolute; + display: block; + left: 0px; + top: 0px; + z-index: 100; + list-style: none; + padding-left: 0px; + margin-left: 0px; + padding: 3px; + .ui-menu-item { + list-style-type: none; + a { + padding: 2px; + padding-left: 4px; + border-radius: 3px; + display: block; + color: rgba(0, 0, 0, 0.6); + cursor: pointer; + text-decoration: none; + &.ui-state-focus, &.ui-state-active { + background: rgba(11, 26, 51, 1); + color: #fff; + } + } + } +} + +.app-top-margin { + margin-top: 15px +} + +.list-link { + float: right; + display: inline; + margin-top: -23px; +} + +.dropdown-menu { + li { + a { + &.list-url { + padding: 0px 4px 0px 4px; + margin-right: 30px; + } + + &.list-remove { + padding: 0px 4px 0px 4px; + margin-right: 10px; + } + } + } +} + +.remote-icon { + background: url('./images/remoteIcon.svg'); + width: 12px; + height: 10px; + display: inline-block; +} + +.branch-icon { + background: url('./images/branchIcon.svg'); + width: 9px; + height: 10px; + display: inline-block; +} + +.tag-icon { + background: url('./images/tagIcon.svg'); + width: 5px; + height: 10px; + display: inline-block; +} diff --git a/src-react/styles/variables.scss b/src-react/styles/variables.scss new file mode 100644 index 0000000..43a2d40 --- /dev/null +++ b/src-react/styles/variables.scss @@ -0,0 +1,32 @@ +@import "~bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss"; + +// -- Application specific variables ---- +$log-width-small: 400px; +$log-width-large: 550px; + +// -- Bootstrap variables --- +$navbar-default-bg: #2B3844; +$font-family-sans-serif: 'Open Sans'; +$font-family-monospace: 'Source Code Pro'; +$body-bg: #252833; +$progress-bg: rgba(0, 0, 0, 0.2); +$progress-bar-bg: rgba(0, 0, 0, 0.2); +$text-color: #D8D8D8; +$text-muted: #707A85; +$panel-bg: #3C4653; +$panel-default-text: $text-color; +$panel-default-heading-bg: #2C3541; +$panel-default-border: #362C36; +$list-group-bg: transparent; +$list-group-hover-bg: rgba(0, 0, 0, 0.2); +$list-group-border: #435158; +$list-group-link-heading-color: rgba(255, 255, 255, 0.8); +$list-group-link-color: rgba(255, 255, 255, 0.5); +$modal-content-bg: $panel-bg; +$modal-header-border-color: $list-group-border; +$input-bg: rgba(255, 255, 255, 0.1); +$input-color-placeholder: rgba(255, 255, 255, 0.3); +$btn-default-bg: #556666; +$btn-default-color: $text-color; +$btn-default-border: rgba(0, 0, 0, 0.1); +$link-hover-color: lighten($link-color, 15%);