Skip to content

Instantly share code, notes, and snippets.

@adrielTosi
Created April 11, 2020 05:57
Show Gist options
  • Save adrielTosi/9621ff61e8492b482850c137fe49e0f3 to your computer and use it in GitHub Desktop.
Save adrielTosi/9621ff61e8492b482850c137fe49e0f3 to your computer and use it in GitHub Desktop.
Example of a styled button design
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { lighten } from 'polished';
import { omit } from 'lodash';
import { fonts, heights, widths, weights } from 'feedr/components/layouts';
import { legacyColors, colors } from 'feedr/theme';
const spinnerWhite = require('./img/loading-white.svg');
const spinnerBlack = require('./img/loading-black.svg');
const plusIcon = require('./img/plus.svg');
const propTypes = {
loading: PropTypes.bool,
secondary: PropTypes.bool,
size: PropTypes.string,
onClick: PropTypes.func,
fullWidth: PropTypes.bool,
type: PropTypes.string,
className: PropTypes.string,
disabled: PropTypes.bool,
href: PropTypes.string,
to: PropTypes.string,
children: PropTypes.node,
plain: PropTypes.bool,
warning: PropTypes.bool,
icon: PropTypes.string,
iconPos: PropTypes.string,
width: PropTypes.number,
};
const defaultProps = {
loading: false,
secondary: false,
size: 'medium',
fullWidth: false,
type: 'button',
className: '',
disabled: false,
href: '',
to: '',
children: '',
onClick: () => null,
plain: false,
warning: false,
icon: null,
iconPos: 'after',
width: undefined,
};
const Wrapper = styled.span`
${p => p.fullWidth && 'width: 100%;'}
button.fdr-input, a.fdr-input {
display: inline-flex;
align-items: center;
justify-content: center;
appearance: none;
border-radius: ${heights.buttonMedium / 2}px;
background: ${colors.avocado};
color: #FFF;
text-transform: capitalize;
padding: 0 1.5em;
margin: 0;
min-height: ${heights.buttonMedium}px;
border: 2px solid ${colors.avocado};
cursor: pointer;
transition: all .2s;
font-family: ${fonts.sourceSans};
font-weight: ${weights.medium};
font-size: 13pt;
${p => !p.width && `
min-width: ${widths.buttonMin}px;
`}
${p => p.width && `
width: ${p.width}px;
`}
&.full-width {
display: inline-block;
width: 100% !important;
}
.spinner {
width: 32px;
height: 32px;
}
&.plain {
display: inline-block;
background: transparent;
color: ${colors.avocado};
border: none;
appearance: none;
padding: 0;
min-width: auto;
text-transform: none;
font-weight: normal;
font-family: ${fonts.gilroy};
&:hover {
background: transparent;
color: #000;
}
}
&:hover {
background-color: ${lighten(0.05, colors.avocado)};
border-color: ${lighten(0.05, colors.avocado)};
}
&.btn-small {
min-height: ${heights.buttonSmall}px;
border-radius: ${heights.buttonSmall / 2}px;
font-size: 11pt;
}
&.btn-large {
min-height: ${heights.buttonLarge}px;
border-radius: ${heights.buttonLarge / 2}px;
font-size: 14pt;
}
&.btn-secondary {
border: solid 1px #ededed;
color: ${colors.avocado};
background-color: #FFF;
&:hover {
border-color: ${colors.avocado};
color: ${colors.avocado};
background-color: #FFF;
}
}
&[disabled] {
background: ${colors.pepper_30};
border-color: ${colors.pepper_30};
cursor: default;
&:hover {
background: ${legacyColors.greyCopySecondary};
color: #FFF;
}
}
&.warning {
background: ${legacyColors.feedrPink};
border: 2px solid ${legacyColors.feedrPink};
}
&:focus {
outline: none;
box-shadow: none;
}
}
`;
const Icon = styled.img`
width: 20px;
height: 20px;
margin: 0 5px;
`;
const Button = function Button(props) {
const doNothing = (e) => {
e.preventDefault();
};
const onClick = (e) => {
e.preventDefault();
e.stopPropagation();
props.onClick();
};
let className = 'fdr-input';
if (!props.secondary) {
className += ' btn-primary';
} else {
className += ' btn-secondary';
}
switch (props.size) {
case 'large':
className += ' btn-large';
break;
case 'small':
className += ' btn-small';
break;
default:
break;
}
if (props.fullWidth) {
className += ' full-width';
}
if (props.plain) {
className += ' plain';
}
if (props.warning) {
className += ' warning';
}
className += ` ${props.className}`;
if (props.loading) {
return (
<Wrapper width={props.width} fullWidth={props.fullWidth}>
<button disabled={props.disabled} className={`${className} loading`} onClick={doNothing}>
{!props.secondary ? (
<img
alt="Loading"
src={spinnerWhite}
width="30"
height="30"
className="spinner"
/>
) :
(
<img
alt="Loading"
src={spinnerBlack}
width="30"
height="30"
className="spinner"
/>
)}
</button>
</Wrapper>
);
}
let icon = null;
if (props.icon === 'plus') {
icon = <Icon alt="" src={plusIcon} />;
}
if (props.href !== '') {
const ommitedProps = omit(props, Object.keys(propTypes));
return (
<Wrapper width={props.width} fullWidth={props.fullWidth}>
<a {...ommitedProps} onClick={props.onClick} className={className} href={props.href}>
{props.iconPos === 'before' && icon}
{props.children}
{props.iconPos === 'after' && icon}
</a>
</Wrapper>);
}
if (props.to !== '') {
return (
<Wrapper width={props.width} fullWidth={props.fullWidth}>
<Link onClick={props.onClick} className={className} to={props.to}>
{props.iconPos === 'before' && icon}
{props.children}
{props.iconPos === 'after' && icon}
</Link>
</Wrapper>
);
}
return (
<Wrapper width={props.width} fullWidth={props.fullWidth}>
<button disabled={props.disabled} className={className} onClick={onClick} type={props.type}>
{props.iconPos === 'before' && icon}
{props.children}
{props.iconPos === 'after' && icon}
</button>
</Wrapper>
);
};
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
export default Button;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment