initial styling

This commit is contained in:
Sebastian Sdorra
2018-07-11 14:59:01 +02:00
parent e3caa93aa7
commit d35a56e07e
18 changed files with 6742 additions and 116 deletions

View File

@@ -4,6 +4,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"bulma": "^0.7.1",
"classnames": "^2.2.5",
"history": "^4.7.2",
"react": "^16.4.1",
@@ -19,8 +20,12 @@
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
"start-js": "react-scripts start",
"start": "npm-run-all -p watch-css start-js",
"build-js": "react-scripts build",
"build": "npm-run-all build-css build-js",
"test": "jest",
"eject": "react-scripts eject",
"flow": "flow"
@@ -35,6 +40,8 @@
"enzyme-adapter-react-16": "^1.1.1",
"flow-bin": "^0.75.0",
"flow-typed": "^2.5.1",
"node-sass-chokidar": "^1.3.0",
"npm-run-all": "^4.1.3",
"prettier": "^1.13.7",
"react-test-renderer": "^16.4.1"
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -19,7 +19,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>SCM-Manager</title>
</head>
<body>
<noscript>

View File

@@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "SCM-Manager",
"name": "SCM-Manager",
"icons": [
{
"src": "favicon.ico",

View File

@@ -0,0 +1,31 @@
//@flow
import React from "react";
import Logo from "./Logo";
type Props = {
children?: React.Node
};
class Header extends React.Component<Props> {
render() {
const { children } = this.props;
return (
<section className="hero is-dark is-small">
<div className="hero-body">
<div className="container">
<div className="columns is-vcentered">
<div className="column">
<Logo />
</div>
</div>
</div>
</div>
<div className="hero-foot">
<div className="container">{children}</div>
</div>
</section>
);
}
}
export default Header;

View File

@@ -0,0 +1,49 @@
//@flow
import React from "react";
import Image from "../images/logo.png";
type Props = {
label?: string,
placeholder?: string,
type?: string,
onChange: string => void
};
class InputField extends React.Component<Props> {
static defaultProps = {
type: "text",
placeholder: ""
};
handleInput = (event: SyntheticInputEvent<HTMLInputElement>) => {
this.props.onChange(event.target.value);
};
renderLabel = () => {
const label = this.props.label;
if (label) {
return <label class="label">{label}</label>;
}
return "";
};
render() {
const { type, placeholder } = this.props;
return (
<div class="field">
{this.renderLabel()}
<div class="control">
<input
class="input"
type={type}
placeholder={placeholder}
onChange={this.handleInput}
/>
</div>
</div>
);
}
}
export default InputField;

View File

@@ -0,0 +1,11 @@
//@flow
import React from "react";
import Image from "../images/logo.png";
class Logo extends React.PureComponent {
render() {
return <img src={Image} alt="SCM-Manager logo" />;
}
}
export default Logo;

View File

@@ -0,0 +1,17 @@
//@flow
import React from "react";
import PrimaryNavigationLink from "./PrimaryNavigationLink";
class PrimaryNavigation extends React.Component<Props> {
render() {
return (
<nav className="tabs is-boxed">
<ul>
<PrimaryNavigationLink to="/users">Users</PrimaryNavigationLink>
</ul>
</nav>
);
}
}
export default PrimaryNavigation;

View File

@@ -0,0 +1,29 @@
//@flow
import React from "react";
import { Route, Link } from "react-router-dom";
type Props = {
to: string,
activeOnlyWhenExact?: boolean,
children?: React.Node
};
class PrimaryNavigationLink extends React.Component<Props> {
renderLink = (route: any) => {
const { to, children } = this.props;
return (
<li className={route.match ? "is-active" : ""}>
<Link to={to}>{children}</Link>
</li>
);
};
render() {
const { to, activeOnlyWhenExact } = this.props;
return (
<Route path={to} exact={activeOnlyWhenExact} children={this.renderLink} />
);
}
}
export default PrimaryNavigationLink;

View File

@@ -0,0 +1,38 @@
//@flow
import React from "react";
import Logo from "./Logo";
import classNames from "classnames";
type Props = {
value: string,
large?: boolean,
fullWidth?: boolean
};
class SubmitButton extends React.Component<Props> {
render() {
const { value, large, fullWidth } = this.props;
const largeClass = large ? "is-large" : "";
const fullWidthClass = fullWidth ? "is-fullwidth" : "";
return (
<div className="field">
<div className="control">
<input
type="submit"
className={classNames(
"button",
"is-link",
largeClass,
fullWidthClass
)}
value={value}
/>
</div>
</div>
);
}
}
export default SubmitButton;

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,14 @@
import React, { Component } from "react";
import Navigation from "./Navigation";
import Main from "./Main";
import Login from "./Login";
import { getIsAuthenticated } from "../modules/login";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import "./App.css";
import Header from "../components/Header";
import PrimaryNavigation from "../components/PrimaryNavigation";
type Props = {
login: boolean,
username: string,
@@ -18,26 +21,28 @@ class App extends Component<Props> {
this.props.getAuthState();
}
render() {
const { login, username, loading } = this.props;
const { login, loading } = this.props;
let content;
let navigation;
if (loading) {
return <div>Loading...</div>;
content = <div>Loading...</div>;
} else if (!login) {
return (
<div>
<Login />
</div>
);
content = <Login />;
} else {
content = <Main />;
navigation = <PrimaryNavigation />;
}
return (
<div className="App">
<h2>Welcome, {username}!</h2>
<Navigation />
<Main />
<Header>{navigation}</Header>
{content}
</div>
);
}
}
}
const mapDispatchToProps = dispatch => {
return {

View File

@@ -0,0 +1,30 @@
@import "bulma/sass/utilities/initial-variables";
@import "bulma/sass/utilities/functions";
$blue: #33B2E8;
// $footer-background-color
.is-ellipsis-overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-rounded-border {
border-radius: 0.25rem;
}
.is-full-width {
width: 100%;
}
.fitParent {
// TODO get rid of important
margin: 0 !important;
// 3.8em for line-numbers
padding: 0 0 0 3.8em !important;
}
// 6. Import the rest of Bulma
@import "bulma/bulma";

View File

@@ -4,15 +4,30 @@ import injectSheet from "react-jss";
import { login } from "../modules/login";
import { connect } from "react-redux";
import InputField from "../components/InputField";
import SubmitButton from "../components/SubmitButton";
import classNames from "classnames";
import Avatar from "../images/blib.jpg";
const styles = {
wrapper: {
width: "100%",
display: "flex",
height: "10em"
spacing: {
paddingTop: "5rem"
},
login: {
margin: "auto",
textAlign: "center"
avatar: {
marginTop: "-70px",
paddingBottom: "20px"
},
avatarImage: {
border: "1px solid lightgray",
padding: "5px",
background: "#fff",
borderRadius: "50%",
width: "128px",
height: "128px"
},
avatarSpacing: {
marginTop: "5rem"
}
};
@@ -32,13 +47,13 @@ class Login extends React.Component<Props, State> {
this.state = { username: "", password: "" };
}
handleUsernameChange(event: SyntheticInputEvent<HTMLInputElement>) {
this.setState({ username: event.target.value });
}
handleUsernameChange = (value: string) => {
this.setState({ username: value });
};
handlePasswordChange(event: SyntheticInputEvent<HTMLInputElement>) {
this.setState({ password: event.target.value });
}
handlePasswordChange = (value: string) => {
this.setState({ password: value });
};
handleSubmit(event: Event) {
event.preventDefault();
@@ -48,24 +63,37 @@ class Login extends React.Component<Props, State> {
render() {
const { classes } = this.props;
return (
<div className={classes.wrapper}>
<div className={classes.login}>
You need to log in! ...
<section className="hero is-fullheight">
<div className={classes.spacing}>
<div className="container has-text-centered">
<div className="column is-4 is-offset-4">
<h3 className="title">Login</h3>
<p className="subtitle">Please login to proceed.</p>
<div className={classNames("box", classes.avatarSpacing)}>
<figure className={classes.avatar}>
<img
className={classes.avatarImage}
src={Avatar}
alt="SCM-Manager"
/>
</figure>
<form onSubmit={this.handleSubmit.bind(this)}>
<input
type="text"
defaultValue="Username"
onChange={this.handleUsernameChange.bind(this)}
<InputField
placeholder="Your Username"
onChange={this.handleUsernameChange}
/>
<input
<InputField
placeholder="Your Password"
type="password"
defaultValue="Password"
onChange={this.handlePasswordChange.bind(this)}
onChange={this.handlePasswordChange}
/>
<input type="submit" value="Login" />
<SubmitButton value="Login" fullWidth={true} />
</form>
</div>
</div>
</div>
</div>
</section>
);
}
}

View File

@@ -1,38 +1,36 @@
//@flow
import React from 'react';
import injectSheet from 'react-jss';
import classNames from 'classnames';
import React from "react";
import injectSheet from "react-jss";
import classNames from "classnames";
import { Route, withRouter } from 'react-router';
import { Route, withRouter } from "react-router";
import Repositories from '../repositories/containers/Repositories';
import Users from '../users/containers/Users';
import {Switch} from 'react-router-dom';
import Repositories from "../repositories/containers/Repositories";
import Users from "../users/containers/Users";
import { Switch } from "react-router-dom";
const styles = {
content: {
paddingTop: '60px'
},
paddingTop: "60px"
}
};
type Props = {
classes: any
}
};
class Main extends React.Component<Props> {
render() {
const { classes } = this.props;
return (
<div className={classNames('container', classes.content)}>
<div className={classNames("container", classes.content)}>
<Switch>
<Route exact path="/" component={Repositories} />
<Route exact path="/users" component={Users} />
<Route path="/users" component={Users} />
</Switch>
</div>
);
}
}
export default withRouter(injectSheet(styles)(Main));

View File

@@ -1,52 +0,0 @@
//@flow
import React from 'react';
import {Link} from 'react-router-dom';
type Props = {};
type State = {
collapsed: boolean
};
class Navigation extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
collapsed: true
};
}
toggleCollapse = () => {
this.setState({
collapsed: !this.state.collapsed
});
};
render() {
return (
<nav className="navbar navbar-default navbar-fixed-top">
<div className="container">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse"
data-target="#navbar" aria-expanded="false" aria-controls="navbar"
onClick={this.toggleCollapse}>
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<Link className="navbar-brand" to="/">
SCM 2 Test UI
</Link>
</div>
</div>
</nav>
);
}
}
export default Navigation;

BIN
scm-ui/src/images/blib.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
scm-ui/src/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB