Added Google and Facebook login, added styling for login form
This commit is contained in:
1184
package-lock.json
generated
1184
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -6,10 +6,12 @@
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"@typescript-eslint/eslint-plugin": "^2.2.0",
|
||||
"@typescript-eslint/parser": "^2.2.0",
|
||||
"autoprefixer": "^9.6.5",
|
||||
"babel-eslint": "10.0.3",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babel-plugin-named-asset-import": "^0.3.4",
|
||||
"babel-preset-react-app": "^9.0.2",
|
||||
"bootstrap": "^4.3.1",
|
||||
"camelcase": "^5.2.0",
|
||||
"case-sensitive-paths-webpack-plugin": "2.2.0",
|
||||
"css-loader": "2.1.1",
|
||||
@@ -25,6 +27,7 @@
|
||||
"eslint-plugin-react-hooks": "^1.6.1",
|
||||
"file-loader": "3.0.1",
|
||||
"fs-extra": "7.0.1",
|
||||
"gapi-script": "0.0.5",
|
||||
"html-webpack-plugin": "4.0.0-beta.5",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"is-wsl": "^1.1.0",
|
||||
@@ -32,15 +35,18 @@
|
||||
"jest-environment-jsdom-fourteen": "0.1.0",
|
||||
"jest-resolve": "24.9.0",
|
||||
"jest-watch-typeahead": "0.4.0",
|
||||
"jquery": "^3.4.1",
|
||||
"mini-css-extract-plugin": "0.8.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"pnp-webpack-plugin": "1.5.0",
|
||||
"popper.js": "^1.16.0",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-normalize": "7.0.1",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"postcss-safe-parser": "4.0.1",
|
||||
"precss": "^4.0.0",
|
||||
"react": "^16.10.2",
|
||||
"react-app-polyfill": "^1.0.4",
|
||||
"react-dev-utils": "^9.1.0",
|
||||
@@ -70,7 +76,9 @@
|
||||
"start": "node scripts/start.js",
|
||||
"build": "node scripts/build.js",
|
||||
"test": "node scripts/test.js",
|
||||
"generate": "plop"
|
||||
"generate": "plop",
|
||||
"server": "node-env-run server --exec nodemon | pino-colada",
|
||||
"dev": "run-p server start"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
@@ -148,8 +156,16 @@
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"@babel/preset-react": "^7.6.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"express-pino-logger": "^4.0.0",
|
||||
"node-env-run": "^3.0.2",
|
||||
"nodemon": "^1.19.4",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pino-colada": "^1.4.5",
|
||||
"plop": "^2.5.2",
|
||||
"webpack": "^4.41.0",
|
||||
"webpack-cli": "^3.3.9"
|
||||
}
|
||||
},
|
||||
"proxy": "http://localhost:3001"
|
||||
}
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<meta name="google-signin-client_id" content="59720049592-8vg2ne03m148cdru5ko9t7upjn5retoe.apps.googleusercontent.com">
|
||||
<script src="https://apis.google.com/js/platform.js" async defer></script>
|
||||
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&autoLogAppEvents=1&version=v4.0&appId=445645186070378"></script>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<link rel="stylesheet" type="text/css" href="./index.css" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
|
||||
17
server/index.js
Normal file
17
server/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const pino = require('express-pino-logger')();
|
||||
|
||||
const app = express();
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(pino);
|
||||
|
||||
app.get('/api/greeting', (req, res) => {
|
||||
const name = req.query.name || 'World';
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.send(JSON.stringify({ greeting: `Hello ${name}!` }));
|
||||
});
|
||||
|
||||
app.listen(3001, () =>
|
||||
console.log('Express server is running on localhost:3001')
|
||||
);
|
||||
@@ -6,12 +6,12 @@ const InputField = ({meta}) => {
|
||||
return (
|
||||
<div className={styles['c-InputField']}>
|
||||
<div
|
||||
className={`form-wrapper__form-row c-form-field ${
|
||||
className={`form-group row ${
|
||||
meta.container_class ? meta.container_class : ''
|
||||
}`}
|
||||
aria-required={meta.aria_required}
|
||||
>
|
||||
<label htmlFor={meta.id}>
|
||||
<label htmlFor={meta.id} className="col-12 col-sm-3 col-lg-12 col-form-label">
|
||||
{meta.validation.required.isRequired && !meta.isStandAloneField && (
|
||||
<span className="required-indicator">* </span>
|
||||
)}
|
||||
@@ -20,12 +20,12 @@ const InputField = ({meta}) => {
|
||||
{meta.secondaryLabel ? (
|
||||
<span className="field--label-description">{meta.secondaryLabel}</span>
|
||||
) : null}
|
||||
<div className="form-wrapper__field-wrapper">
|
||||
<div className="col-12 col-sm-9 col-12">
|
||||
{meta.error && (
|
||||
<span className="form-wrapper__field-error">{meta.errorMessage}</span>
|
||||
)}
|
||||
<input
|
||||
className={meta.error ? 'error' : ''}
|
||||
className={`form-control ${meta.error ? 'error' : ''}`}
|
||||
type={meta.type}
|
||||
id={meta.id}
|
||||
name={meta.name}
|
||||
@@ -38,6 +38,7 @@ const InputField = ({meta}) => {
|
||||
required={meta.validation.required.isRequired ? 'required' : ''}
|
||||
minLength={meta.validation.rules.minlength}
|
||||
maxLength={meta.validation.rules.maxlength}
|
||||
placeholder={meta.placeholder}
|
||||
aria-required={meta.aria_required}
|
||||
aria-invalid={meta.aria_invalid}
|
||||
// onFocus={onBlurProp ? onBlurProp : this.onFocusHandler}
|
||||
@@ -50,6 +51,7 @@ const InputField = ({meta}) => {
|
||||
}
|
||||
onFocus={meta.handlers.onFocusHandler}
|
||||
onChange={meta.handlers.onChangeHandler}
|
||||
style={{width: '100%'}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
.c-InputField {
|
||||
margin-bottom: 20px;
|
||||
label {
|
||||
float: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
// label {
|
||||
// float: left;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// margin-right: 10px;
|
||||
// }
|
||||
input[type="text"],input[type="password"] {
|
||||
padding: 5px;
|
||||
width: 70%;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* PLOP_INJECT_IMPORT */
|
||||
import SideBar from './SideBar';
|
||||
import Jumbotron from './Jumbotron';
|
||||
import FormFieldContainer from './FormFieldContainer';
|
||||
import Form from './Form';
|
||||
import SocialLogin from './SocialLogin';
|
||||
@@ -10,6 +12,8 @@ import PageLoader from './PageLoader';
|
||||
|
||||
export {
|
||||
/* PLOP_INJECT_EXPORT */
|
||||
SideBar,
|
||||
Jumbotron,
|
||||
FormFieldContainer,
|
||||
Form,
|
||||
SocialLogin,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
.c-login {
|
||||
// Root Class. Contains all core styles, typically for the component's
|
||||
// wrapper element.
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classNames from 'classnames'
|
||||
|
||||
class Login extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
text
|
||||
} = this.props
|
||||
|
||||
const classes = classNames('c-login', {
|
||||
// 'c--modifier': bool ? true : false
|
||||
}, className)
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
I am an example! {text}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Login.propTypes = {
|
||||
/**
|
||||
* PropTypes comments are REQUIRED for components to be included
|
||||
* in the styleguide
|
||||
*/
|
||||
text: PropTypes.string.isRequired,
|
||||
|
||||
/**
|
||||
* Adds values to the attribute of the root element
|
||||
*/
|
||||
className: PropTypes.string,
|
||||
|
||||
}
|
||||
|
||||
export default Login
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './LoginForm.module.css';
|
||||
import styles from './LoginForm.module.scss';
|
||||
|
||||
import loginFormFields from './../../../config/forms-meta/login-form.json'
|
||||
import Form from './../common/Form'
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.c-LoginForm {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.c-LoginForm {
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -1,9 +1,18 @@
|
||||
import React from 'react';
|
||||
import styles from './PageLoader.module.scss';
|
||||
|
||||
const PageLoader = props => {
|
||||
return (
|
||||
<div className="c-page-loader">
|
||||
<p>Loading...</p>
|
||||
<div className={styles['c-PageLoader']}>
|
||||
<div className={styles['is-animate']}>
|
||||
<div className={styles.l}>l</div>
|
||||
<div className={styles.l}>o</div>
|
||||
<div className={styles.l}>a</div>
|
||||
<div className={styles.l}>d</div>
|
||||
<div className={styles.l}>i</div>
|
||||
<div className={styles.l}>n</div>
|
||||
<div className={styles.l}>g</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.c-PageLoader {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Indie+Flower');
|
||||
|
||||
.c-PageLoader {
|
||||
margin-top: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.is-animate {
|
||||
background: #ffb200;
|
||||
box-sizing: border-box;
|
||||
font-size: 66px;
|
||||
display: -webkit-inline-box;
|
||||
padding: 14px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.is-animate > div {
|
||||
animation-name: style;
|
||||
display: -webkit-inline-box;
|
||||
color: #fff;
|
||||
padding: 9px;
|
||||
background: #ffb200;
|
||||
font-family: 'Indie Flower', cursive;
|
||||
box-shadow: 2px 2px 9px 2px;
|
||||
}
|
||||
.l{
|
||||
animation: letterspacing 1s infinite alternate cubic-bezier(.2, 0, 0, 1);
|
||||
}
|
||||
|
||||
.is-animate > div {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.is-animate > div:nth-child(1) { animation-delay: 0.0s }
|
||||
.is-animate > div:nth-child(2) { animation-delay: 0.1s }
|
||||
.is-animate > div:nth-child(3) { animation-delay: 0.2s }
|
||||
.is-animate > div:nth-child(4) { animation-delay: 0.3s }
|
||||
.is-animate > div:nth-child(5) { animation-delay: 0.4s }
|
||||
.is-animate > div:nth-child(6) { animation-delay: 0.5s }
|
||||
.is-animate > div:nth-child(7) { animation-delay: 0.6s }
|
||||
|
||||
|
||||
@keyframes style {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
30% {
|
||||
box-shadow: 0px 0px 0px 0px;
|
||||
transform: scale3d(1.25, 0.75, 1);
|
||||
}
|
||||
40% {
|
||||
transform: scale3d(0.75, 1.25, 1);
|
||||
}
|
||||
50% {
|
||||
transform: scale3d(1.15, 0.85, 1);
|
||||
}
|
||||
65% {
|
||||
transform: scale3d(.95, 1.05, 1);
|
||||
}
|
||||
75% {
|
||||
transform: scale3d(1.05, .95, 1);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes letterspacing {
|
||||
0% {
|
||||
filter: blur(0.1rem);
|
||||
}
|
||||
100% {
|
||||
filter: blur(0.5rem);
|
||||
}
|
||||
to {
|
||||
letter-spacing: none;
|
||||
filter: blur(0rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/app/components/molecules/SideBar/SideBar.js
Normal file
52
src/app/components/molecules/SideBar/SideBar.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './SideBar.module.scss';
|
||||
|
||||
const SideBar = props => {
|
||||
// return (
|
||||
// <nav id="sidebar" class="active">
|
||||
// <div class="sidebar-header">
|
||||
// <button type="button" id="sidebarCollapse" class="btn btn-info">
|
||||
// <i class="fas fa-align-justify"></i>
|
||||
// </button>
|
||||
// <h3 class="logotext">Microbot</h3>
|
||||
// <!-- <strong>MB</strong> -->
|
||||
// </div>
|
||||
|
||||
// <ul class="list-unstyled components">
|
||||
// <li *ngFor="let tab of tabsData"
|
||||
// [ngClass]="{active: tab.activeClass}">
|
||||
// <a [routerLink]="tab.href">
|
||||
// <i [ngClass]="['fas', tab.tabImage]"></i>
|
||||
// <span class="hideable hide">{{tab.tabText}}</span>
|
||||
// </a>
|
||||
// <ul
|
||||
// class="collapse list-unstyled"
|
||||
// id="pageSubmenu"
|
||||
// *ngIf="tab.subList">
|
||||
// <li>
|
||||
// <a href="#">Repo</a>
|
||||
// </li>
|
||||
// <li>
|
||||
// <a href="#">Issues</a>
|
||||
// </li>
|
||||
// <li>
|
||||
// <a href="#">Admin</a>
|
||||
// </li>
|
||||
// </ul>
|
||||
// </li>
|
||||
// </ul>
|
||||
// </nav>
|
||||
// );
|
||||
return null
|
||||
};
|
||||
|
||||
SideBar.defaultProps = {
|
||||
|
||||
};
|
||||
|
||||
SideBar.propTypes = {
|
||||
|
||||
};
|
||||
|
||||
export default SideBar;
|
||||
459
src/app/components/molecules/SideBar/SideBar.module.scss
Normal file
459
src/app/components/molecules/SideBar/SideBar.module.scss
Normal file
@@ -0,0 +1,459 @@
|
||||
$themeColor-Light: #EEE2DC;
|
||||
// $themeColor-Dark:#252525;
|
||||
$themeColor-Dark:#E3E2DF;
|
||||
$theme-font: verdana, sans-serif;
|
||||
// $theme-supplementer: #f39c12;
|
||||
$theme-supplementer: #5D001E;
|
||||
$theme-supplementer-transparent: rgba(93,0,30,0.3);
|
||||
|
||||
.c-SideBar {
|
||||
background: $theme-supplementer-transparent;
|
||||
z-index: 20;
|
||||
|
||||
p {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
font-size: 1.1em;
|
||||
font-weight: 300;
|
||||
line-height: 1.7em;
|
||||
// color: #999;
|
||||
}
|
||||
|
||||
a,
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
padding: 15px 10px;
|
||||
background: #fff;
|
||||
border: none;
|
||||
border-radius: 0 5px 5px 0;
|
||||
margin-bottom: 40px;
|
||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.navbar-btn {
|
||||
box-shadow: none;
|
||||
outline: none !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-bottom: 1px dashed #ddd;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
i,
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------
|
||||
SIDEBAR STYLE
|
||||
----------------------------------------------------- */
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
background-color: $themeColor-Dark;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
// background: $theme-supplementer-transparent;
|
||||
color: $themeColor-Dark;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
#sidebar.active {
|
||||
min-width: 80px;
|
||||
max-width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#sidebar.active .sidebar-header h3,
|
||||
#sidebar.active .CTAs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-header h3 {
|
||||
display: inline;
|
||||
padding-left: 0.6em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#sidebar.active .sidebar-header strong {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#sidebar ul li a {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#sidebar.active ul li a {
|
||||
padding: 20px 10px;
|
||||
text-align: center;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
#sidebar.active ul li a i {
|
||||
margin-right: 0;
|
||||
display: block;
|
||||
font-size: 1.8em;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#sidebar.active ul ul a {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
#sidebar.active .dropdown-toggle::after {
|
||||
top: auto;
|
||||
bottom: 10px;
|
||||
right: 50%;
|
||||
-webkit-transform: translateX(50%);
|
||||
-ms-transform: translateX(50%);
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
#sidebar .sidebar-header {
|
||||
padding: 20px;
|
||||
background:$themeColor-Dark;
|
||||
}
|
||||
|
||||
#sidebar .sidebar-header strong {
|
||||
display: none;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#sidebar ul.components {
|
||||
padding: 20px 0;
|
||||
border-bottom: 3px solid $themeColor-Dark;
|
||||
}
|
||||
|
||||
#sidebar ul li a {
|
||||
padding: 10px;
|
||||
font-size: 1.1em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#sidebar ul li a:hover {
|
||||
color: $theme-supplementer;
|
||||
background: $themeColor-Light;
|
||||
}
|
||||
|
||||
#sidebar ul li a i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#sidebar ul li.active>a,
|
||||
a[aria-expanded="true"] {
|
||||
color: $theme-supplementer;
|
||||
background:$themeColor-Dark;
|
||||
}
|
||||
|
||||
a[data-toggle="collapse"] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-toggle::after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 20px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
ul ul a {
|
||||
font-size: 0.9em !important;
|
||||
padding-left: 30px !important;
|
||||
background: white;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
ul.CTAs {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
ul.CTAs a {
|
||||
text-align: center;
|
||||
font-size: 0.9em !important;
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
a.download {
|
||||
background: #fff;
|
||||
color: #7386D5;
|
||||
}
|
||||
|
||||
a.article,
|
||||
a.article:hover {
|
||||
background: #6d7fcc !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------
|
||||
CONTENT STYLE
|
||||
----------------------------------------------------- */
|
||||
|
||||
#content {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
min-height: 100vh;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------
|
||||
MEDIAQUERIES
|
||||
----------------------------------------------------- */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#sidebar {
|
||||
min-width: 80px;
|
||||
max-width: 80px;
|
||||
text-align: center;
|
||||
margin-left: -80px !important;
|
||||
}
|
||||
.dropdown-toggle::after {
|
||||
top: auto;
|
||||
bottom: 10px;
|
||||
right: 50%;
|
||||
-webkit-transform: translateX(50%);
|
||||
-ms-transform: translateX(50%);
|
||||
transform: translateX(50%);
|
||||
}
|
||||
#sidebar.active {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
#sidebar .sidebar-header h3,
|
||||
#sidebar .CTAs {
|
||||
display: none;
|
||||
}
|
||||
#sidebar .sidebar-header strong {
|
||||
display: block;
|
||||
}
|
||||
#sidebar ul li a {
|
||||
padding: 20px 10px;
|
||||
}
|
||||
#sidebar ul li a span {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
#sidebar ul li a i {
|
||||
margin-right: 0;
|
||||
display: block;
|
||||
}
|
||||
#sidebar ul ul a {
|
||||
padding: 10px !important;
|
||||
}
|
||||
#sidebar ul li a i {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
#sidebar {
|
||||
margin-left: 0;
|
||||
}
|
||||
#sidebarCollapse span {
|
||||
display: none;
|
||||
}
|
||||
.text-muted {
|
||||
color: #bcb !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 576px) {
|
||||
.card-group>.card:first-child {
|
||||
border-top-right-radius: .25rem;
|
||||
border-bottom-right-radius: .25rem;
|
||||
}
|
||||
.card-group>.card:not(:first-child):not(:last-child):not(:only-child) {
|
||||
border-radius: .25rem;
|
||||
}
|
||||
.card-group>.card:last-child {
|
||||
border-top-left-radius: .25rem;
|
||||
border-bottom-left-radius: .25rem;
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------------
|
||||
ADDITIONS
|
||||
--------------------------------------------------*/
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
display: flex;
|
||||
width: 2em;
|
||||
border-right: 1px solid #c99034;
|
||||
// background-color: #f5d38b;
|
||||
background-color: $theme-supplementer;
|
||||
width: 4%;
|
||||
margin-bottom: 40px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.promptext {
|
||||
animation:blinkingText 0.8s infinite;
|
||||
// color: #975f04;
|
||||
// color: $themeColor-Light;
|
||||
text-align: center;
|
||||
line-height: 2em;
|
||||
font: 1.5em bolder;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.good {
|
||||
animation: anim .3s ease-in-out;
|
||||
}
|
||||
|
||||
.repoLink {
|
||||
color: #000;
|
||||
font-weight: bolder;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.headerprompt {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logotext {
|
||||
color: $theme-supplementer;
|
||||
}
|
||||
|
||||
#content nav div.collapse li a.nav-link i.far {
|
||||
color: $theme-supplementer;
|
||||
font-size: 1.8em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
#loading-img {
|
||||
background: url(http://preloaders.net/preloaders/360/Velocity.gif) center center no-repeat;
|
||||
height: 100%;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
background: #e9e9e9;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 0px solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border-top: 2px solid #3498db;
|
||||
border-right: 2px solid #3498db;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
.card:not(.widget) {
|
||||
background: linear-gradient(to right, white, lightblue)
|
||||
}
|
||||
.light-red {
|
||||
// background:linear-gradient(white, lightblue);
|
||||
background: linear-gradient(to right, white, #dfc99a)
|
||||
}
|
||||
|
||||
// f3d98c
|
||||
.featureRequest {
|
||||
background-color : #007bff;
|
||||
color: white;
|
||||
font-size: 1.5em;
|
||||
padding: 10px 20px;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
#featureRequest {
|
||||
position: fixed;
|
||||
bottom: 2em;
|
||||
right: 2.5em;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes anim {
|
||||
0% {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
1% {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@keyframes blinkingText {
|
||||
0%{ color: $themeColor-Light; }
|
||||
49%{ color: transparent; }
|
||||
50%{ color: transparent; }
|
||||
99%{ color:transparent; }
|
||||
100%{ color: $themeColor-Light; }
|
||||
}
|
||||
|
||||
/* --------------------------------------------------
|
||||
OVERRIDES
|
||||
--------------------------------------------------*/
|
||||
.btn:not(.featureRequest) {
|
||||
background-color: $theme-supplementer;
|
||||
color: $themeColor-Dark
|
||||
}
|
||||
|
||||
#content #header .navbar {
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
.navbar-form {
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding: .6rem 1em;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
|
||||
.card-group {
|
||||
flex-direction:column;
|
||||
}
|
||||
|
||||
#command.form-control {
|
||||
width: 92%;
|
||||
}
|
||||
|
||||
.ml-auto {
|
||||
margin-left: 0!important;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
border-color: orange;
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
border-color: orange;
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
8
src/app/components/molecules/SideBar/SideBar.test.js
Normal file
8
src/app/components/molecules/SideBar/SideBar.test.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import SideBar from './SideBar';
|
||||
|
||||
describe('SideBar', () => {
|
||||
it('renders without error', () => {
|
||||
|
||||
});
|
||||
});
|
||||
3
src/app/components/molecules/SideBar/index.js
Normal file
3
src/app/components/molecules/SideBar/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import SideBar from './SideBar';
|
||||
|
||||
export default SideBar;
|
||||
@@ -1,13 +1,62 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './SocialLogin.module.css';
|
||||
import {withRouter} from 'react-router-dom'
|
||||
import {gapi} from 'gapi-script'
|
||||
import styles from './SocialLogin.module.scss';
|
||||
|
||||
const SocialLogin = props => {
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
class SocialLogin extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.width = 254
|
||||
this.height = 50
|
||||
this.onSuccess = this.onSuccess.bind(this)
|
||||
this.onFailure = this.onFailure.bind(this)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
gapi.signin2.render('g-signin2', {
|
||||
'scope': 'profile email',
|
||||
'width': this.width,
|
||||
'height': this.height,
|
||||
'longtitle': true,
|
||||
'theme': 'dark',
|
||||
'onsuccess': this.onSuccess,
|
||||
'onfailure': this.onFailure
|
||||
});
|
||||
}
|
||||
|
||||
onSuccess(googleUser) {
|
||||
console.log('Logged in as: ' + googleUser.getBasicProfile().getName());
|
||||
this.props.history.push('/home')
|
||||
}
|
||||
|
||||
onFailure(error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles['c-SocialLogin']}>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="g-signin2" id="g-signin2"></div>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<div
|
||||
className="fb-login-button"
|
||||
data-width={this.width}
|
||||
data-height={this.height}
|
||||
data-size="large"
|
||||
data-button-type="continue_with"
|
||||
data-auto-logout-link="false"
|
||||
data-use-continue-as="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SocialLogin.defaultProps = {
|
||||
|
||||
@@ -17,4 +66,4 @@ SocialLogin.propTypes = {
|
||||
|
||||
};
|
||||
|
||||
export default SocialLogin;
|
||||
export default withRouter(SocialLogin)
|
||||
@@ -1,3 +0,0 @@
|
||||
.c-SocialLogin {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.c-SocialLogin {
|
||||
padding: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.abcRioButtonBlue {
|
||||
background: white;
|
||||
color: #585f6b;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,29 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import * as styles from './Form.module.css'
|
||||
import * as styles from './Form.module.scss'
|
||||
import FormFieldContainer from '../FormFieldContainer';
|
||||
|
||||
class Form extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
name: '',
|
||||
greeting: ''
|
||||
};
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.onFocusHandler = this.onFocusHandler.bind(this)
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({ name: event.target.value });
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
fetch(`/api/greeting?name=${encodeURIComponent(this.state.name)}`)
|
||||
.then(response => response.json())
|
||||
.then(state => this.setState(state));
|
||||
}
|
||||
|
||||
onFocusHandler() {
|
||||
@@ -39,7 +56,7 @@ class Form extends React.Component {
|
||||
onFocus={this.onFocusHandler}
|
||||
customBlurHandler={
|
||||
formFieldObject.impactsShippingOptions ||
|
||||
formFieldObject.id === 'number'
|
||||
formFieldObject.id === 'number'
|
||||
? customBlurHandler
|
||||
: null
|
||||
}
|
||||
@@ -60,7 +77,12 @@ class Form extends React.Component {
|
||||
return formFieldObject !== null
|
||||
})
|
||||
|
||||
return <fieldset className={styles['c-Form']}>{inputListSection}</fieldset>
|
||||
return (
|
||||
<form className={styles['c-Form']} onSubmit={this.handleSubmit}>
|
||||
<fieldset>{inputListSection}</fieldset>
|
||||
<button type="submit" className="btn btn-primary btn-block" style={{marginTop: '15px', background: 'black'}}>Submit</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
.c-Form {
|
||||
padding: 15px;
|
||||
/* width: 400px; */
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 40px;
|
||||
border: 1px solid lightgrey;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.c-Form {
|
||||
padding: 15px;
|
||||
background: #ddd;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 3px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
28
src/app/components/molecules/common/Jumbotron/Jumbotron.js
Normal file
28
src/app/components/molecules/common/Jumbotron/Jumbotron.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types'
|
||||
import styles from './Jumbotron.module.scss';
|
||||
import {Link} from 'react-router-dom'
|
||||
|
||||
const Jumbotron = props => {
|
||||
return (
|
||||
<div className={`${styles['c-Jumbotron']} jumbotron`}>
|
||||
<h1 className="display-4">{props.jumboText}</h1>
|
||||
<p className="lead">{props.subText}</p>
|
||||
<hr className={`${styles['my-4']} my-4`}/>
|
||||
<p>{props.jumboDescription}</p>
|
||||
<p className="lead">
|
||||
<Link className="btn btn-primary btn-lg" to="#" role="button">Let's get started</Link>
|
||||
<Link className="btn btn-primary btn-lg float-right" to="#" role="button" style={{marginLeft: '15px'}}>{props.furtherLink}</Link>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Jumbotron.propTypes = {
|
||||
furtherLink: PropTypes.string,
|
||||
jumboDescription: PropTypes.string,
|
||||
jumboText: PropTypes.string,
|
||||
subText: PropTypes.string
|
||||
};
|
||||
|
||||
export default Jumbotron;
|
||||
@@ -0,0 +1,8 @@
|
||||
.c-Jumbotron {
|
||||
background: #222;
|
||||
color: #bbbbbb;
|
||||
margin-bottom: 0;
|
||||
.my-4 {
|
||||
border-color: #bbb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import Jumbotron from './Jumbotron';
|
||||
|
||||
describe('Jumbotron', () => {
|
||||
it('renders without error', () => {
|
||||
|
||||
});
|
||||
});
|
||||
3
src/app/components/molecules/common/Jumbotron/index.js
Normal file
3
src/app/components/molecules/common/Jumbotron/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Jumbotron from './Jumbotron';
|
||||
|
||||
export default Jumbotron;
|
||||
@@ -2,7 +2,7 @@
|
||||
"login": {
|
||||
"email": {
|
||||
"label": "Email ID",
|
||||
"placeholder": "Please enter your email ID...",
|
||||
"placeholder": "Email ID",
|
||||
"type": "text",
|
||||
"id": "email",
|
||||
"elementType": "input",
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"password": {
|
||||
"label": "Password",
|
||||
"placeholder": "Select a strong password...",
|
||||
"placeholder": "Password",
|
||||
"type": "password",
|
||||
"id": "password",
|
||||
"elementType": "input",
|
||||
|
||||
@@ -7,6 +7,8 @@ import {createPropsSelector} from 'reselect-immutable-helpers'
|
||||
import * as actions from './actions'
|
||||
import {getHome} from './selectors'
|
||||
|
||||
import Sidebar from './../../components/molecules/side-bar'
|
||||
|
||||
class Home extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
@@ -21,8 +23,7 @@ class Home extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.Home}>
|
||||
<h1 className="u-padding-top-md u-margin-bottom-sm">Home page</h1>
|
||||
<p className="u-margin-bottom-md">Tips for getting started on this page:</p>
|
||||
<Sidebar />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './Login.module.scss';
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import styles from './Login.module.scss'
|
||||
import {connect} from 'react-redux'
|
||||
import {createPropsSelector} from 'reselect-immutable-helpers'
|
||||
|
||||
@@ -8,6 +8,7 @@ import * as actions from './actions'
|
||||
import {getLogin, getFormErrors, getFormValues} from './selectors'
|
||||
import LoginForm from '../../components/molecules/LoginForm'
|
||||
import SocialLogin from '../../components/molecules/SocialLogin'
|
||||
import Jumbotron from '../../components/molecules/common/Jumbotron/Jumbotron'
|
||||
|
||||
class Login extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -21,20 +22,32 @@ class Login extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log("in login")
|
||||
const {updateFormErrors, updateFormValues, formErrors, formValues} = this.props
|
||||
return (
|
||||
<div className={styles.Login}>
|
||||
<h1 className="u-padding-top-md u-margin-bottom-sm">Welcome to Ecstatica</h1>
|
||||
<p className="u-margin-bottom-md">Please login to continue</p>
|
||||
<LoginForm
|
||||
updateFormValues={updateFormValues}
|
||||
updateFormErrors={updateFormErrors}
|
||||
formErrors={formErrors}
|
||||
formValues={formValues}
|
||||
/>
|
||||
<p className={styles.loginSplitter}>OR</p>
|
||||
<SocialLogin />
|
||||
<div className={`${styles.Login} container`}>
|
||||
<div className="row">
|
||||
<div className="col-12 col-lg-8">
|
||||
<Jumbotron
|
||||
jumboText="Welcome To Ecstatica"
|
||||
subText="Show us what you've got!"
|
||||
jumboDescription="An app for professional photographers, to provide a window to the world, to demonstrate the art within."
|
||||
furtherLink="Learn more"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12 col-lg-4">
|
||||
<div className={styles.loginContainer}>
|
||||
<p className={styles['c-login-intimation']}>Let's get to know each other, shall we!</p>
|
||||
<LoginForm
|
||||
updateFormValues={updateFormValues}
|
||||
updateFormErrors={updateFormErrors}
|
||||
formErrors={formErrors}
|
||||
formValues={formValues}
|
||||
/>
|
||||
<p className={styles.loginSplitter}>OR</p>
|
||||
<SocialLogin />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
.Login {
|
||||
.loginSplitter {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
text-transform: capitalize;
|
||||
font-size: 25px;
|
||||
font-weight: bolder;
|
||||
line-height: 30px;
|
||||
background: #222;
|
||||
max-width: unset;
|
||||
@media only screen and (max-width: 1140px) {
|
||||
padding-left: unset;
|
||||
padding-right: unset;
|
||||
margin-right: unset;
|
||||
margin-left: unset;
|
||||
}
|
||||
.loginContainer {
|
||||
border: 2px solid grey;
|
||||
border-radius: 0.3rem;
|
||||
margin: 1rem;
|
||||
background: #eee;
|
||||
padding-bottom: 20px;
|
||||
.c-login-intimation {
|
||||
padding: 15px 5px 15px 15px;
|
||||
background: black;
|
||||
color: white;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.loginSplitter {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: capitalize;
|
||||
font-size: 25px;
|
||||
font-weight: bolder;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #222!important;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
@@ -11,3 +12,17 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
|
||||
.abcRioButtonBlue {
|
||||
background-color: white!important;
|
||||
color: #585f6b!important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.g-signin2, .fb-login-button {
|
||||
display: flex!important;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import {createStore, applyMiddleware} from 'redux'
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
import Router from './app/router';
|
||||
import reducer from './app/reducer'
|
||||
import './index.css'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
|
||||
const store = createStore(reducer, applyMiddleware(thunk))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user