First attempt at CSS modules (#48)

* README proposal.

* First pass at implementation of proposal on Footer and Header. Footer could use some work.

* Cleanup, and readme additions
This commit is contained in:
William O'Beirne 2017-07-15 00:16:36 -04:00 committed by Daniel Ternyak
parent c9948626d1
commit 8ed09dfa06
18 changed files with 874 additions and 392 deletions

View File

@ -46,3 +46,71 @@ You should already have docker and docker-compose setup for your platform as a p
```bash
docker-compose up
```
## Style Guides and Philosophies
The following are guides for developers to follow for writing compliant code.
### Styling
Legacy styles are housed under `common/assets/styles` and written with LESS.
However, going forward, each styled component should create a a `.scss` file of
the same name in the same folder, and import it like so:
```js
import React from "react";
import "./MyComponent.scss";
export default class MyComponent extends React.component {
render() {
return (
<div className="MyComponent">
<div className="MyComponent-child">Hello!</div>
</div>
);
}
}
```
These style modules adhere to [SuitCSS naming convention](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md):
```scss
.MyComponent {
/* Styles */
&-child {
/* Styles */
&.is-hidden {
display: none;
}
}
}
```
All elements inside of a component should extend its parent class namespace, or
create a new namespace (Potentially breaking that out into its own component.)
Variables and mixins can be imported from the files in `common/styles`:
```scss
@import "sass/colors";
code {
color: $code-color;
}
```
#### Converting Styles
When working on a module that has styling in Less, try to do the following:
* Screenshot the component in question
* Create a new SCSS file in the same directory
* Remove styling from LESS file, convert it to the SCSS file (Mostly s/@/$)
* Convert class names to SuitCSS naming convention
* Convert any utility classes from `etherewallet-utilities.less` into mixins
* Convert as many element selectors to class name selectors as possible
* Convert as many `<br/>` tags or `&nbsp;`s to margins
* Ensure that there has been little to no deviation from screenshot

View File

@ -7,60 +7,6 @@ textarea {
resize: vertical;
}
// footer
footer {
background-color: @ether-navy;
color: white;
margin-top: 100px;
padding-top: @space-xs;
padding-bottom: @space-sm;
img {
width: 100%;
height: auto;
max-width: 20rem;
}
p {
margin: @space-xs 0 @space-sm;
}
a {
color: #4ac8ed;
&:hover,
&:focus {
color: darken(#4ac8ed, 5%);
}
}
.modal,
.modal p {
color: @text-color;
}
h5 {
font-size: @font-size-bump;
margin: @font-size-small 0 0;
i {
margin-left: -1.5em;
margin-right: .25em;
}
}
ul {
list-style: none;
padding-left: @space-sm;
margin: 0 0 @space-xs 0;
}
li, p {
font-size: @font-size-small;
margin: @space-sm 0;
}
.footer-2, .footer-3 {
padding-left: 3rem;
}
@media screen and (max-width: @grid-float-breakpoint) {
.row {
margin-left: -.5rem;
margin-right: -.5rem;
}
}
}
// anouncement bars
.announcement {
padding: 3px 10px;
@ -91,7 +37,8 @@ footer {
&:hover,
&:focus {
background-color: darken(@brand-danger, 5%);
a, a:hover {
a,
a:hover {
text-decoration: none;
}
}
@ -102,7 +49,8 @@ footer {
a:hover,
a:focus {
color: darken(white, 5%);
a, a:hover {
a,
a:hover {
text-decoration: none;
}
}
@ -145,7 +93,8 @@ footer {
background-size: cover;
background-repeat: no-repeat;
border-radius: 50%;
box-shadow: inset rgba(255, 255, 255, 0.5) 0 2px 2px, inset rgba(0, 0, 0, 0.6) 0 -1px 8px;
box-shadow: inset rgba(255, 255, 255, 0.5) 0 2px 2px,
inset rgba(0, 0, 0, 0.6) 0 -1px 8px;
}
.addressIdenticon.med {
@ -187,7 +136,11 @@ footer {
}
.account-help-icon {
h3, h4, h5, h6, img {
h3,
h4,
h5,
h6,
img {
display: inline-block;
}
img:hover + .account-help-text {
@ -202,13 +155,13 @@ footer {
.account-help-text {
background: white;
border-radius: @border-radius;
border: 1px solid #CDCDCD;
border: 1px solid #cdcdcd;
box-shadow: 0 0 @space-sm rgba(100, 100, 100, .2);
display: none;
font-size: @font-size-xs;
font-weight: 400;
padding: @space-xs;
position: absolute;;
position: absolute;
width: 18rem;
z-index: 999;
ul& {
@ -318,7 +271,8 @@ input[type="password"] + .eye {
// collapsable containers
.collapse-container {
h2, h4 {
h2,
h4 {
cursor: pointer;
}
.collapse-button {
@ -395,7 +349,7 @@ h2 a.isActive {
}
label small {
color: @gray-light
color: @gray-light;
}
.write-address {
@ -507,7 +461,8 @@ label small {
}
@keyframes opacity {
from, to {
from,
to {
opacity: 0;
}
50% {

View File

@ -48,6 +48,4 @@
@import "etherwallet-swap.less";
@import "etherwallet-ext-custom.less";
@import "etherwallet-utilities.less";
@import "etherwallet-nav.less";
@import "etherwallet-print.less";

View File

@ -1,189 +0,0 @@
// Header
.header-branding {
color: white;
padding: 0;
@media screen and (max-width: 900px) {
text-align: center;
}
.container {
display: flex;
align-items: center;
@media screen and (max-width: 900px) {
flex-direction: column;
padding-left: @cont-padding;
padding-right: @cont-padding;
}
}
.brand {
@media screen and (min-width: 901px) {
flex-basis: 245px;
}
img {
max-width: 1000px;
padding: 5px 0;
min-width: 220px;
}
}
.tagline {
font-size: 18px;
font-weight: 200;
color: white;
flex: 1 auto;
text-align: right;
padding: 5px 0;
@media screen and (max-width: 900px) {
text-align: center;
}
> * {
display: inline;
vertical-align: middle;
}
}
a {
color: white;
cursor: pointer;
font-weight: 400;
transition: 250ms all ease;
}
a:hover,
a:active {
opacity: .8;
color: white;
text-decoration: none;
transition: 250ms all ease;
}
.dropdown {
padding: 0;
text-align: right;
white-space: nowrap;
.dropdown-menu {
right: -10px;
left: auto;
min-width: auto;
left: auto;
& > li > a {
font-size: 15px;
padding: 5px 30px 5px 15px;
position: relative;
}
}
}
}
.dropdown-menu a.active {
text-decoration: none;
color: @brand-primary;
background-color: @gray-lightest;
}
// Navigation
.nav-container {
position: relative;
overflow-y: hidden;
.nav-scroll {
-ms-overflow-style: -ms-autohiding-scrollbar;
-webkit-overflow-scrolling: touch;
overflow-x: auto;
margin-bottom: -20px;
font-size: 0;
white-space: nowrap;
@media screen and (max-width: @screen-sm) {
margin: 0 -5% -20px;
}
.nav-inner {
border-bottom: 2px solid @gray-lighter;
display: inline-block;
font-size: 0;
margin-bottom: 20px;
min-width: 100%;
padding: 5px 0 0;
vertical-align: middle;
.nav-item {
display: inline-block;
font-size: 0;
&.NAV_Swap a:before {
content: "";
display: inline-block;
margin-top: -.1rem;
width: 1.3rem;
height: 1.3rem;
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20620.04%20631.27%22%3E%3Ctitle%3Eicon-swap%3C/title%3E%3Cpath%20d%3D%22M469.95%20289.68c-77%200-139.59-62.62-139.59-139.59S392.98%2010.5%20469.95%2010.5s139.59%2062.62%20139.59%20139.59-62.62%20139.59-139.59%20139.59z%22%20fill%3D%22%23ffe14d%22/%3E%3Cpath%20d%3D%22M469.95%2021a129.09%20129.09%200%201%201-129.09%20129.09A129.24%20129.24%200%200%201%20469.95%2021m0-21c-82.76%200-150.09%2067.33-150.09%20150.09s67.29%20150.09%20150.09%20150.09%20150.09-67.33%20150.09-150.09S552.71%200%20469.95%200z%22%20fill%3D%22%230f0f0f%22/%3E%3Cpath%20d%3D%22M599.04%20150.09A129.24%20129.24%200%200%200%20469.95%2021v258.18a129.24%20129.24%200%200%200%20129.09-129.09z%22%20fill%3D%22%23fc3%22/%3E%3Cpath%20d%3D%22M469.95%2044.94a105.12%20105.12%200%201%200%20105.12%20105.15A105.24%20105.24%200%200%200%20469.95%2044.94zm0%20179c-49.27%200-74.85-24.6-74.85-73.87s25.58-74.85%2074.85-74.85%2075.82%2025.58%2075.82%2074.85-26.55%2073.87-75.82%2073.87z%22%20fill%3D%22%23ff9f19%22/%3E%3Cpath%20d%3D%22M545.77%20150.09c0%2049.27-26.55%2074.85-75.82%2074.85v30.27a105.12%20105.12%200%201%200%200-210.24v30.27c49.27%200%2075.82%2025.58%2075.82%2074.85z%22%20fill%3D%22%23f28618%22/%3E%3Cpath%20fill%3D%22%230492be%22%20d%3D%22M100.66%20277.37H26.9V114.06h240.72V50.84l131.7%20100.1-131.7%20100.09v-63.22H100.66v89.56z%22/%3E%3Cpath%20fill%3D%22%23103957%22%20opacity%3D%22.2%22%20d%3D%22M63.78%20150.94h335.54l-131.7-100.1v63.22H26.9v163.31h36.88V150.94z%22/%3E%3Cpath%20d%3D%22M259.71%2034.94l152.67%20116-152.67%20116v-71.23H108.55v89.56H19V106.15h240.71zm126.55%20116L275.52%2066.77v55.17H34.8v147.53h57.95v-89.53h182.77v55.19z%22/%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M292.951%20119.43l9.638-12.482%2047.456%2036.642-9.638%2012.482z%22/%3E%3Cpath%20d%3D%22M150.09%20620.77c-77%200-139.59-62.62-139.59-139.59s62.65-139.59%20139.59-139.59%20139.59%2062.62%20139.59%20139.59-62.62%20139.59-139.59%20139.59z%22%20fill%3D%22%23ffe14d%22/%3E%3Cpath%20d%3D%22M150.09%20352.09A129.09%20129.09%200%201%201%2021%20481.18a129.24%20129.24%200%200%201%20129.09-129.09m0-21C67.33%20331.09%200%20398.42%200%20481.18s67.33%20150.09%20150.09%20150.09%20150.06-67.33%20150.06-150.09-67.3-150.09-150.06-150.09z%22%20fill%3D%22%230f0f0f%22/%3E%3Cpath%20d%3D%22M21%20481.18a129.24%20129.24%200%200%200%20129.09%20129.09V352.09A129.24%20129.24%200%200%200%2021%20481.18z%22%20fill%3D%22%23fc3%22/%3E%3Cpath%20d%3D%22M150.09%20586.3A105.12%20105.12%200%201%200%2044.97%20481.18%20105.24%20105.24%200%200%200%20150.09%20586.3zm0-179c49.27%200%2074.85%2024.6%2074.85%2073.87s-25.58%2074.85-74.85%2074.85-75.82-25.58-75.82-74.85%2026.55-73.86%2075.82-73.86z%22%20fill%3D%22%23ff9f19%22/%3E%3Cpath%20d%3D%22M74.26%20481.18c0-49.27%2026.55-74.85%2075.82-74.85v-30.27a105.12%20105.12%200%201%200%200%20210.24v-30.27c-49.26%200-75.82-25.58-75.82-74.85z%22%20fill%3D%22%23f28618%22/%3E%3Cpath%20fill%3D%22%230492be%22%20d%3D%22M519.39%20353.9h73.75v163.31H352.43v63.22L220.72%20480.34l131.71-100.1v63.22h166.96V353.9z%22/%3E%3Cpath%20fill%3D%22%23103957%22%20opacity%3D%22.2%22%20d%3D%22M556.26%20480.34H220.72l131.71%20100.09v-63.22h240.71V353.9h-36.88v126.44z%22/%3E%3Cpath%20d%3D%22M360.32%20596.36l-152.66-116%20152.66-116v71.25h151.16V346h89.56v179.11H360.32zm-126.55-116l110.74%2084.16v-55.21h240.73V361.8h-57.95v89.56H344.52v-55.19z%22/%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M268.572%20486.574l9.7-12.473%2047.419%2036.875-9.7%2012.473z%22/%3E%3C/svg%3E);
background-position: center;
background-repeat: no-repeat;
background-size: contain;
vertical-align: middle;
margin-right: @space-xs;
}
a {
color: darken(@link-color, 15%);
display: block;
font-size: 16px;
font-weight: 300;
padding: 10px;
white-space: nowrap;
position: relative;
min-height: 2.75rem;
}
a:after {
content: "";
background: @brand-primary;
height: 2px;
width: 100%;
left: 0px;
position: absolute;
bottom: -1px;
transition: all 250ms ease 0s;
transform: scale(0);
}
&.active a,
a:hover,
a:focus {
color: @brand-primary;
text-decoration: none;
transition: all 250ms ease 0s;
&:after {
transform: scale(1);
transition: all 250ms ease 0s;
}
}
}
}
}
.nav-arrow-right,
.nav-arrow-left {
background-color: white;
bottom: 12px;
color: #d6d6d6;
font-size: 33px;
line-height: 1.3;
min-width: 50px;
position: absolute;
top: 0;
vertical-align: middle;
width: 5%;
z-index: 999;
&:hover {
text-decoration: none;
}
}
.nav-arrow-right {
right: 3%;
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 47%, rgba(255, 255, 255, 1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
padding-right: 5px;
text-align: right;
@media screen and (max-width: @screen-sm) {
right: 0;
}
}
.nav-arrow-left {
left: 3%;
background: linear-gradient(to left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 47%, rgba(255, 255, 255, 1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
padding-left: 5px;
text-align: left;
@media screen and (max-width: @screen-sm) {
left: 0;
}
}
}

View File

@ -20,11 +20,6 @@
background: @ether-navy;
}
.bg-gradient {
background: @ether-navy;
background: linear-gradient(149deg, #132a45, #143a56, #21a4ce, #19b4ad);
}
.bg-gray-lighter {
background-color: @gray-lighter;
}

View File

@ -3,18 +3,21 @@ import translate, { getTranslators } from 'translations';
import { donationAddressMap } from 'config/data';
import logo from 'assets/images/logo-myetherwallet.svg';
import './index.scss';
export default class Footer extends Component {
render() {
const translators = getTranslators();
return (
<footer role="contentinfo" aria-label="footer">
<footer className="Footer" role="contentinfo" aria-label="footer">
<div className="container">
<section className="row">
<section className="row">
<div className="col-sm-3 footer-1">
<div className="Footer-about col-sm-3">
<p aria-hidden="true">
<a href="/">
<img
className="Footer-about-logo"
src={logo}
height="55px"
width="auto"
@ -43,7 +46,8 @@ export default class Footer extends Component {
</p>
<br />
</div>
<div className="col-sm-6 footer-2">
<div className="Footer-info col-sm-6">
<h5>
<i aria-hidden="true">💝</i>
{translate('FOOTER_2')}
@ -107,7 +111,8 @@ export default class Footer extends Component {
</li>
</ul>}
</div>
<div className="col-sm-3 footer-3">
<div className="Footer-links col-sm-3">
<h5>
<i aria-hidden="true">🌎</i> On the Web
</h5>

View File

@ -0,0 +1,62 @@
@import "common/sass/variables";
// footer
.Footer {
background-color: $ether-navy;
color: white;
margin-top: 100px;
padding-top: $space-xs;
padding-bottom: $space-sm;
&-logo {
width: 100%;
height: auto;
max-width: 20rem;
}
&-info,
&-links {
padding-left: 3rem;
}
p {
margin: $space-xs 0 $space-sm;
}
a {
color: #4ac8ed;
&:hover,
&:focus {
color: darken(#4ac8ed, 5%);
}
}
h5 {
font-size: $font-size-bump;
margin: $font-size-small 0 0;
i {
margin-left: -1.5em;
margin-right: .25em;
}
}
ul {
list-style: none;
padding-left: $space-sm;
margin: 0 0 $space-xs 0;
}
li,
p {
font-size: $font-size-small;
margin: $space-sm 0;
}
@media screen and (max-width: $grid-float-breakpoint) {
.row {
margin-left: -.5rem;
margin-right: -.5rem;
}
}
}

View File

@ -0,0 +1,110 @@
import React, { Component } from 'react';
import { Link } from 'react-router';
import translate from 'translations';
import PropTypes from 'prop-types';
import './Navigation.scss';
const tabs = [
{
name: 'NAV_GenerateWallet',
link: '/'
},
{
name: 'NAV_SendEther',
link: 'send-transaction'
},
{
name: 'NAV_Swap',
link: 'swap'
},
{
name: 'NAV_Offline'
},
{
name: 'NAV_Contracts'
},
{
name: 'NAV_ViewWallet',
link: 'view-wallet'
},
{
name: 'NAV_Help',
link: 'help'
}
];
export default class TabsOptions extends Component {
constructor(props) {
super(props);
this.state = {
showLeftArrow: false,
showRightArrow: false
};
}
static propTypes = {
location: PropTypes.object
};
tabClick() {}
scrollLeft() {}
scrollRight() {}
render() {
const { location } = this.props;
return (
<nav
role="navigation"
aria-label="main navigation"
className="Navigation container overflowing"
>
{this.state.showLeftArrow &&
<a
aria-hidden="true"
className="Navigation-arrow Navigation-arrow--left"
onClick={() => this.scrollLeft(100)}
>
&#171;
</a>}
<div className="Navigation-scroll">
<ul className="Navigation-links">
{tabs.map((object, i) => {
// if the window pathname is the same or similar to the tab objects name, set the active toggle
const activeOrNot =
location.pathname === object.link ||
location.pathname.substring(1) === object.link
? 'is-active'
: '';
return (
<li
className={'Navigation-links-item'}
key={i}
onClick={this.tabClick(i)}
>
<Link
className={`Navigation-links-item-link ${activeOrNot}`}
to={object.link}
aria-label={`nav item: ${translate(object.name)}`}
>
{translate(object.name)}
</Link>
</li>
);
})}
</ul>
</div>
{this.state.showRightArrow &&
<a
aria-hidden="true"
className="Navigation-arrow Navigation-arrow-right"
onClick={() => this.scrollRight(100)}
>
&#187;
</a>}
</nav>
);
}
}

View File

@ -0,0 +1,116 @@
@import "common/sass/variables";
.Navigation {
position: relative;
overflow-y: hidden;
&-scroll {
-ms-overflow-style: -ms-autohiding-scrollbar;
-webkit-overflow-scrolling: touch;
overflow-x: auto;
margin-bottom: -20px;
font-size: 0;
white-space: nowrap;
@media screen and (max-width: $screen-sm) {
margin: 0 -5% -20px;
}
}
&-links {
border-bottom: 2px solid $gray-lighter;
display: inline-block;
font-size: 0;
margin-bottom: 20px;
min-width: 100%;
padding: 5px 0 0;
vertical-align: middle;
&-item {
display: inline-block;
font-size: 0;
&-link {
color: darken($link-color, 15%);
display: block;
font-size: 16px;
font-weight: 300;
padding: 10px;
white-space: nowrap;
position: relative;
min-height: 2.75rem;
&:after {
content: "";
background: $brand-primary;
height: 2px;
width: 100%;
left: 0px;
position: absolute;
bottom: -1px;
transition: all 250ms ease 0s;
transform: scaleX(0);
}
&.is-active,
&:hover,
&:focus {
color: $brand-primary;
text-decoration: none;
transition: all 250ms ease 0s;
&:after {
transform: scaleX(1);
transition: all 250ms ease 0s;
}
}
}
}
}
&-arrow {
background-color: white;
bottom: 12px;
color: #d6d6d6;
font-size: 33px;
line-height: 1.3;
min-width: 50px;
position: absolute;
top: 0;
vertical-align: middle;
width: 5%;
z-index: 999;
&:hover {
text-decoration: none;
}
&--left {
left: 3%;
background: linear-gradient(
to left,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 1) 47%,
rgba(255, 255, 255, 1) 100%
);
padding-left: 5px;
text-align: left;
@media screen and (max-width: $screen-sm) {
left: 0;
}
}
&--right {
right: 3%;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 1) 47%,
rgba(255, 255, 255, 1) 100%
);
padding-right: 5px;
text-align: right;
@media screen and (max-width: $screen-sm) {
right: 0;
}
}
}
}

View File

@ -1,108 +0,0 @@
import React, { Component } from 'react';
import { Link } from 'react-router';
import translate from 'translations';
import PropTypes from 'prop-types';
const tabs = [
{
name: 'NAV_GenerateWallet',
link: '/'
},
{
name: 'NAV_SendEther',
link: 'send-transaction'
},
{
name: 'NAV_Swap',
link: 'swap'
},
{
name: 'NAV_Offline'
},
{
name: 'NAV_Contracts'
},
{
name: 'NAV_ViewWallet',
link: 'view-wallet'
},
{
name: 'NAV_Help',
link: 'help'
}
];
export default class TabsOptions extends Component {
constructor(props) {
super(props);
this.state = {
showLeftArrow: false,
showRightArrow: false
};
}
static propTypes = {
location: PropTypes.object
};
tabClick() {}
scrollLeft() {}
scrollRight() {}
render() {
const { location } = this.props;
return (
<div>
<nav
role="navigation"
aria-label="main navigation"
className="container nav-container overflowing"
>
{this.state.showLeftArrow &&
<a
aria-hidden="true"
className="nav-arrow-left"
onClick={() => this.scrollLeft(100)}
>
&#171;
</a>}
<div className="nav-scroll">
<ul className="nav-inner">
{tabs.map((object, i) => {
// if the window pathname is the same or similar to the tab objects name, set the active toggle
const activeOrNot = location.pathname === object.link ||
location.pathname.substring(1) === object.link
? 'active'
: '';
return (
<li
className={`nav-item ${activeOrNot}`}
key={i}
onClick={this.tabClick(i)}
>
<Link
to={object.link}
aria-label={`nav item: ${translate(object.name)}`}
>
{translate(object.name)}
</Link>
</li>
);
})}
</ul>
</div>
{this.state.showRightArrow &&
<a
aria-hidden="true"
className="nav-arrow-right"
onClick={() => this.scrollRight(100)}
>
&#187;
</a>}
</nav>
</div>
);
}
}

View File

@ -1,13 +1,16 @@
// @flow
import React, { Component } from 'react';
import TabsOptions from './components/TabsOptions';
import Navigation from './components/Navigation';
import { Link } from 'react-router';
import { Dropdown } from 'components/ui';
import { languages, NODES } from '../../config/data';
import logo from 'assets/images/logo-myetherwallet.svg';
import './index.scss';
export default class Header extends Component {
props: {
location: {},
languageSelection: string,
nodeSelection: string,
@ -22,17 +25,28 @@ export default class Header extends Component {
const selectedNode = NODES[nodeSelection];
return (
<div>
<section className="bg-gradient header-branding">
<section className="container">
<Link to={'/'} className="brand" aria-label="Go to homepage">
<img src={logo} height="64px" width="245px" alt="MyEtherWallet" />
<div className="Header">
<section className="Header-branding">
<section className="Header-branding-inner container">
<Link
to={'/'}
className="Header-branding-title"
aria-label="Go to homepage"
>
{/* TODO - don't hardcode image path*/}
<img
className="Header-branding-title-logo"
src={logo}
height="64px"
width="245px"
alt="MyEtherWallet"
/>
</Link>
<div className="tagline">
<div className="Header-branding-title-tagline">
<span style={{ maxWidth: '395px' }}>
Open-Source & Client-Side Ether Wallet · v3.6.0
</span>
&nbsp;&nbsp;&nbsp;
<Dropdown
ariaLabel={`change language. current language ${selectedLanguage.name}`}
options={languages}
@ -48,7 +62,7 @@ export default class Header extends Component {
]}
onChange={this.changeLanguage}
/>
&nbsp;&nbsp;&nbsp;
<Dropdown
ariaLabel={`change node. current node ${selectedNode.network} node by ${selectedNode.service}`}
options={Object.keys(NODES)}
@ -71,7 +85,7 @@ export default class Header extends Component {
</section>
</section>
<TabsOptions {...this.props} />
<Navigation location={this.props.location} />
</div>
);
}

View File

@ -0,0 +1,109 @@
@import "common/sass/variables";
@import "common/sass/mixins";
$small-size: 900px;
@mixin small-query {
@media screen and (max-width: $small-size) {
@content;
}
}
@mixin big-query {
@media screen and (min-width: $small-size + 1) {
@content;
}
}
// Header
.Header {
&-branding {
color: white;
padding: 0;
@include bg-gradient;
@include small-query {
text-align: center;
}
&-inner {
display: flex;
align-items: center;
@include small-query {
flex-direction: column;
padding-left: $cont-padding;
padding-right: $cont-padding;
}
}
&-title {
@include big-query {
flex-basis: 245px;
}
&-logo {
max-width: 1000px;
padding: 5px 0;
min-width: 220px;
}
&-tagline {
font-size: 18px;
font-weight: 200;
color: white;
flex: 1 auto;
text-align: right;
padding: 5px 0;
@include small-query {
text-align: center;
}
> * {
display: inline;
vertical-align: middle;
}
}
}
a {
color: white;
cursor: pointer;
font-weight: 400;
transition: 250ms all ease;
&:hover,
&:active {
opacity: .8;
color: white;
text-decoration: none;
transition: 250ms all ease;
}
}
// TODO - Move to dropdown component?
.dropdown {
margin-left: 15px;
padding: 0;
text-align: right;
white-space: nowrap;
.dropdown-menu {
right: -10px;
left: auto;
min-width: auto;
left: auto;
& > li > a {
font-size: 15px;
padding: 5px 30px 5px 15px;
position: relative;
&.active {
text-decoration: none;
color: $brand-primary;
background-color: $gray-lightest;
}
}
}
}
}
}

6
common/sass/mixins.scss Normal file
View File

@ -0,0 +1,6 @@
@import "./variables";
@mixin bg-gradient {
background: $ether-navy;
background: linear-gradient(149deg, #132a45, #143a56, #21a4ce, #19b4ad);
}

281
common/sass/variables.scss Normal file
View File

@ -0,0 +1,281 @@
@import "./variables/colors";
@import "./variables/spacing";
@import "./variables/typography";
// Transitions
$transition: 500ms all ease-in-out;
// Links
$link-color: $brand-primary;
$link-hover-color: darken($link-color, 5%);
$link-hover-decoration: none;
// Tables
$table-cell-padding: $space-sm;
$table-condensed-cell-padding: $space-xs;
$table-bg: transparent;
$table-bg-accent: #f9f9f9;
$table-bg-hover: $gray-lightest;
$table-bg-active: $table-bg-hover;
$table-border-color: #ddd;
// Buttons
$btn-font-weight: normal;
$btn-default-color: #333;
$btn-default-bg: #ececec;
$btn-default-border: $gray-lighter;
$btn-primary-color: #fff;
$btn-primary-bg: $brand-primary;
$btn-primary-border: darken($btn-primary-bg, 5%);
$btn-success-color: #fff;
$btn-success-bg: $brand-success;
$btn-success-border: darken($btn-success-bg, 5%);
$btn-info-color: #fff;
$btn-info-bg: $brand-info;
$btn-info-border: darken($btn-info-bg, 5%);
$btn-warning-color: #fff;
$btn-warning-bg: $brand-warning;
$btn-warning-border: darken($btn-warning-bg, 5%);
$btn-danger-color: #fff;
$btn-danger-bg: $brand-danger;
$btn-danger-border: darken($btn-danger-bg, 5%);
$btn-link-disabled-color: $gray-light;
// Forms
$input-bg: #fff;
$input-bg-disabled: $gray-lightest;
$input-color: $gray;
$input-border: $gray-lighter;
$input-border-focus: $brand-primary;
$input-color-placeholder: darken($gray-lighter, 10%);
$input-height-base: 2.55rem;
$input-height-large: 4rem;
$input-height-small: 2rem;
$form-group-margin-bottom: $space-sm;
$legend-color: $gray-dark;
$legend-border-color: #e5e5e5;
$input-group-addon-bg: $gray-lighter;
$input-group-addon-border-color: $input-border;
// Misc.
$cursor-disabled: default;
$dropdown-bg: #fff;
$dropdown-border: rgba(0, 0, 0, .15);
$dropdown-fallback-border: $gray-lighter;
$dropdown-divider-bg: #e5e5e5;
$dropdown-link-color: $ether-navy;
$dropdown-link-hover-color: $ether-blue;
$dropdown-link-hover-bg: $gray-lightest;
$dropdown-link-active-color: $component-active-color;
$dropdown-link-active-bg: $component-active-bg;
$dropdown-link-disabled-color: $gray-light;
$dropdown-header-color: $gray-light;
$dropdown-caret-color: #000;
$zindex-navbar: 1000;
$zindex-dropdown: 1000;
$zindex-popover: 1060;
$zindex-tooltip: 1070;
$zindex-navbar-fixed: 1030;
$zindex-modal-background: 1040;
$zindex-modal: 1050;
$zindex-alerts: 1060;
$screen-xs: 32rem;
$screen-xs-min: $screen-xs;
$screen-sm: 51.2rem;
$screen-sm-min: $screen-sm;
$screen-md: 66.133333333rem;
$screen-md-min: $screen-md;
$screen-lg: 80rem;
$screen-lg-min: $screen-lg;
$screen-xl: 94rem;
$screen-xl-min: $screen-xl;
$screen-xs-max: ($screen-sm-min - 1);
$screen-sm-max: ($screen-md-min - 1);
$screen-md-max: ($screen-lg-min - 1);
$screen-lg-max: ($screen-xl-min - 1);
$grid-columns: 12;
$grid-gutter-width: 3rem;
$grid-float-breakpoint: $screen-sm-min;
$grid-float-breakpoint-max: ($grid-float-breakpoint - 1);
$cont-padding: 5%;
$cont-padding-lg: 7.5%;
$container-tablet: ($screen-sm + $grid-gutter-width);
$container-sm: $container-tablet;
$container-desktop: ($screen-md + $grid-gutter-width);
$container-md: $container-desktop;
$container-large-desktop: ($screen-lg + $grid-gutter-width);
$container-lg: $container-large-desktop;
$state-success-text: darken($brand-success, 10%);
$state-success-bg: #dff0d8;
$state-success-border: darken(adjust-hue($state-success-bg, -10deg), 5%);
$state-info-text: darken($brand-info, 10%);
$state-info-bg: #d9edf7;
$state-info-border: darken(adjust-hue($state-info-bg, -10deg), 7%);
$state-warning-text: darken($brand-warning, 10%);
$state-warning-bg: #fcf8e3;
$state-warning-border: darken(adjust-hue($state-warning-bg, -10deg), 5%);
$state-danger-text: darken($brand-danger, 10%);
$state-danger-bg: #f2dede;
$state-danger-border: darken(adjust-hue($state-danger-bg, -10deg), 5%);
$tooltip-max-width: 200px;
$tooltip-color: #fff;
$tooltip-bg: #000;
$tooltip-opacity: .9;
$tooltip-arrow-width: $space-sm;
$tooltip-arrow-color: $tooltip-bg;
$label-default-bg: $gray-light;
$label-primary-bg: $brand-primary;
$label-success-bg: $brand-success;
$label-info-bg: $brand-info;
$label-warning-bg: $brand-warning;
$label-danger-bg: $brand-danger;
$label-color: #fff;
$label-link-hover-color: #fff;
$modal-inner-padding: $space*1.5;
$modal-title-padding: $space;
$modal-title-line-height: $line-height-base;
$modal-content-bg: #fff;
$modal-content-border-color: rgba(0, 0, 0, .2);
$modal-content-fallback-border-color: #999;
$modal-backdrop-bg: #000;
$modal-backdrop-opacity: .5;
$modal-header-border-color: #e5e5e5;
$modal-footer-border-color: $modal-header-border-color;
$modal-lg: 70rem;
$modal-md: 50rem;
$modal-sm: 30rem;
$alert-border-radius: $border-radius;
$alert-link-font-weight: bold;
$alert-success-bg: $brand-success;
$alert-success-text: white;
$alert-success-border: $alert-success-bg;
$alert-info-bg: $brand-primary;
$alert-info-text: white;
$alert-info-border: $alert-info-bg;
$alert-warning-bg: $brand-warning;
$alert-warning-text: white;
$alert-warning-border: $alert-warning-bg;
$alert-danger-bg: $brand-danger;
$alert-danger-text: white;
$alert-danger-border: $alert-danger-bg;
$progress-bg: $gray-lightest;
$progress-bar-color: #fff;
$progress-border-radius: $border-radius;
$progress-bar-bg: $brand-primary;
$progress-bar-success-bg: $brand-success;
$progress-bar-warning-bg: $brand-warning;
$progress-bar-danger-bg: $brand-danger;
$progress-bar-info-bg: $brand-info;
$list-group-bg: #fff;
$list-group-border: #ddd;
$list-group-border-radius: $border-radius;
$list-group-hover-bg: $gray-lightest;
$list-group-active-color: $component-active-color;
$list-group-active-bg: $component-active-bg;
$list-group-active-border: $list-group-active-bg;
$list-group-active-text-color: lighten($list-group-active-bg, 40%);
$list-group-disabled-color: $gray-light;
$list-group-disabled-bg: $gray-lighter;
$list-group-disabled-text-color: $list-group-disabled-color;
$list-group-link-color: #555;
$list-group-link-hover-color: $list-group-link-color;
$list-group-link-heading-color: #333;
$thumbnail-padding: 4px;
$thumbnail-bg: $body-bg;
$thumbnail-border: #ddd;
$thumbnail-border-radius: $border-radius;
$thumbnail-caption-color: $text-color;
$thumbnail-caption-padding: 9px;
$well-bg: $gray-lightest;
$well-border: darken($well-bg, 7%);
$badge-font-weight: bold;
$badge-line-height: 1;
$badge-border-radius: 10px;
$close-font-weight: bold;
$close-color: #000;
$close-text-shadow: 0 1px 0 #fff;
$code-color: #c7254e;
$code-bg: #f9f2f4;
$kbd-color: #fff;
$kbd-bg: #333;
$pre-bg: $gray-lightest;
$pre-color: $gray-dark;
$pre-border-color: $gray-lighter;
$pre-scrollable-max-height: 340px;
$component-offset-horizontal: 180px;
$text-muted: $gray-light;
$abbr-border-color: $gray-light;
$headings-small-color: inherit;
$blockquote-small-color: $gray-light;
$blockquote-font-size: ($font-size-base * 1.25);
$blockquote-border-color: $gray-lighter;
$page-header-border-color: $gray-lighter;
$dl-horizontal-offset: $component-offset-horizontal;
$hr-border: $gray-lighter;

View File

@ -0,0 +1,19 @@
$ether-navy: #163151;
$ether-blue: #0e97c0;
$gray-base: #000;
$gray-darker: lighten($gray-base, 13.5%);
$gray-dark: lighten($gray-base, 20%);
$gray: #737373;
$gray-light: #9a9a9a;
$gray-lighter: #ececec;
$gray-lightest: #fafafa;
$brand-primary: $ether-blue;
$brand-success: #5dba5a;
$brand-info: $ether-navy;
$brand-warning: #ff9800;
$brand-danger: #ea4b40;
$body-bg: #fff;
$text-color: $gray-dark;

View File

@ -0,0 +1,29 @@
$space-xs: 0.25rem;
$space-sm: 0.50rem;
$space-md: 0.75rem;
$space: 1.00rem;
$space-lg: 1.50rem;
$space-xl: 2.00rem;
$padding-base-vertical: $space * 0.6;
$padding-base-horizontal: $space;
$padding-large-vertical: $space-md;
$padding-large-horizontal: $space-xl;
$padding-small-vertical: 0.1rem;
$padding-small-horizontal: $space-sm;
$padding-xs-vertical: $space-xs;
$padding-xs-horizontal: 0.2rem;
$line-height-large: 1.2;
$line-height-small: 1.5;
$border-radius: 2px;
$component-active-color: #fff;
$component-active-bg: $brand-primary;
$caret-width-base: $space-xs;
$caret-width-large: $space-xs;

View File

@ -0,0 +1,22 @@
$font-family-sans-serif: 'Lato', sans-serif;
$font-family-serif: Georgia, "Times New Roman", Times, serif;
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
$font-family-base: $font-family-sans-serif;
$base: 15;
$font-size-pixels: $base + px;
$font-size-pixels-xl: $base + 1px; // for xl screens
$font-size-pixels-sm: $base + px; // for small screens
$font-size-large-bump: 2.25rem; // 33.75
$font-size-large: 1.90rem; // 28.5
$font-size-medium-bump: 1.50rem; // 22.5
$font-size-medium: 1.30rem; // 19.5
$font-size-bump-more: 1.15rem; // 17.25
$font-size-bump: 1.07rem; // 16.05
$font-size-base: 1.00rem; // 15
$font-size-small: 0.92rem; // 13.8
$font-size-xs: 0.80rem; // 12
$line-height-base: 1.4;
$line-height-computed: 1.4;

View File

@ -20,19 +20,9 @@ module.exports = {
},
resolve: {
extensions: ['.js', '.jsx', '.css', '.json', '.scss', '.less'],
alias: {
actions: `${config.srcPath}/actions/`,
api: `${config.srcPath}/api/`,
reducers: `${config.srcPath}/reducers/`,
components: `${config.srcPath}/components/`,
containers: `${config.srcPath}/containers/`,
styles: `${config.srcPath}/styles/`,
less_vars: `${config.srcPath}/styles/etherwallet-variables.less`
},
// FIXME why aliases then?
modules: [
// places where to search for required modules
_.cwd('common'),
config.srcPath,
_.cwd('node_modules'),
_.cwd('./')
]