removes redux, renames rem to base, converts all redux components to context
This commit is contained in:
@@ -4,11 +4,11 @@
|
||||
@extend %uppercase-label;
|
||||
background-color: $primary;
|
||||
border: 1px solid $primary;
|
||||
padding: rem(.5) rem(.75);
|
||||
line-height: rem(.5);
|
||||
padding: base(.5) base(.75);
|
||||
line-height: base(.5);
|
||||
border-radius: $radius-sm;
|
||||
margin-top: rem(1);
|
||||
margin-bottom: rem(1);
|
||||
margin-top: base(1);
|
||||
margin-bottom: base(1);
|
||||
cursor: pointer;
|
||||
|
||||
&.btn-secondary {
|
||||
@@ -33,9 +33,9 @@
|
||||
}
|
||||
|
||||
&.btn-small {
|
||||
padding: rem(0) rem(.25) rem(.04);
|
||||
padding: base(0) base(.25) base(.04);
|
||||
border-radius: 3px;
|
||||
font-size: rem(.3);
|
||||
font-size: base(.3);
|
||||
}
|
||||
|
||||
&.btn-text {
|
||||
@@ -55,12 +55,12 @@
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
width: rem(1.5);
|
||||
height: rem(1.5);
|
||||
width: base(1.5);
|
||||
height: base(1.5);
|
||||
|
||||
svg {
|
||||
width: rem(.75);
|
||||
height: rem(.75);
|
||||
width: base(.75);
|
||||
height: base(.75);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
|
||||
.field-type.email {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import React from 'react';
|
||||
import fieldType from '../fieldType';
|
||||
|
||||
const HiddenInput = props => <input type="hidden" value={props.value || ''}
|
||||
onChange={props.onChange} id={props.id ? props.id : props.name} name={props.name} />;
|
||||
const HiddenInput = props => (
|
||||
<input
|
||||
type="hidden"
|
||||
value={props.value || ''}
|
||||
onChange={props.onChange}
|
||||
id={props.id ? props.id : props.name}
|
||||
name={props.name}
|
||||
/>
|
||||
);
|
||||
|
||||
export default fieldType(HiddenInput, 'hiddenInput');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
|
||||
.field-type.input {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
|
||||
.field-type.password {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
|
||||
.field-type.textarea {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
position: relative;
|
||||
|
||||
textarea {
|
||||
@include formInput();
|
||||
min-height: rem(3);
|
||||
min-height: base(3);
|
||||
}
|
||||
|
||||
&.error {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { FormContext } from '../../forms/Form'
|
||||
import FormContext from '../../forms/Form/Context'
|
||||
|
||||
import './index.scss';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.field-type {
|
||||
@include gutter;
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
.required {
|
||||
color: $error;
|
||||
margin-left: rem(.25);
|
||||
margin-left: base(.25);
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
left: auto;
|
||||
right: rem(.5);
|
||||
right: base(.5);
|
||||
transform: none;
|
||||
background-color: $error;
|
||||
|
||||
@@ -28,6 +28,6 @@
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
}
|
||||
}
|
||||
|
||||
3
src/client/components/forms/Form/Context.js
Normal file
3
src/client/components/forms/Form/Context.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export default createContext({});
|
||||
@@ -1,55 +1,50 @@
|
||||
import React, { Component, createContext } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import FormContext from './Context';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { useStatusList } from '../../modules/Status';
|
||||
import HiddenInput from '../../field-types/HiddenInput';
|
||||
import api from '../../../api';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export const FormContext = createContext({});
|
||||
const Form = (props) => {
|
||||
const [fields, setFields] = useState({});
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const history = useHistory();
|
||||
const locale = useLocale();
|
||||
const { addStatus } = useStatusList();
|
||||
|
||||
const mapState = state => ({
|
||||
searchParams: state.common.searchParams
|
||||
})
|
||||
const {
|
||||
onSubmit,
|
||||
ajax,
|
||||
method,
|
||||
action,
|
||||
handleAjaxResponse,
|
||||
children,
|
||||
className,
|
||||
redirect,
|
||||
} = props;
|
||||
|
||||
const mapDispatch = dispatch => ({
|
||||
addStatus: status => dispatch({ type: 'ADD_STATUS', payload: status })
|
||||
})
|
||||
|
||||
class Form extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
fields: {},
|
||||
status: null,
|
||||
submitted: false,
|
||||
processing: false
|
||||
};
|
||||
}
|
||||
|
||||
setValue = field => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
fields: {
|
||||
...prevState.fields,
|
||||
[field.name]: {
|
||||
value: field.value,
|
||||
valid: field.valid
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
submit = e => {
|
||||
this.setState({
|
||||
submitted: true
|
||||
const setValue = (field) => {
|
||||
setFields({
|
||||
...fields,
|
||||
[field.name]: {
|
||||
value: field.value,
|
||||
valid: field.valid,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const submit = (e) => {
|
||||
setSubmitted(true);
|
||||
|
||||
let isValid = true;
|
||||
|
||||
Object.keys(this.state.fields).forEach((field) => {
|
||||
if (!this.state.fields[field].valid) {
|
||||
Object.keys(fields).forEach((field) => {
|
||||
if (!fields[field].valid) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
@@ -59,80 +54,100 @@ class Form extends Component {
|
||||
e.preventDefault();
|
||||
|
||||
// If submit handler comes through via props, run that
|
||||
} else if (this.props.onSubmit) {
|
||||
} else if (onSubmit) {
|
||||
e.preventDefault();
|
||||
this.props.onSubmit(this.state.fields);
|
||||
onSubmit(fields);
|
||||
|
||||
// If form is AJAX, fetch data
|
||||
} else if (this.props.ajax !== false) {
|
||||
} else if (ajax !== false) {
|
||||
e.preventDefault();
|
||||
let data = {};
|
||||
const data = {};
|
||||
|
||||
// Clean up data passed from field state
|
||||
Object.keys(this.state.fields).forEach((field) => {
|
||||
data[field] = this.state.fields[field].value;
|
||||
Object.keys(fields).forEach((field) => {
|
||||
data[field] = fields[field].value;
|
||||
});
|
||||
|
||||
this.setState({
|
||||
processing: true
|
||||
});
|
||||
setProcessing(true);
|
||||
|
||||
// Make the API call from the action
|
||||
api.requests[this.props.method.toLowerCase()](this.props.action, data).then(
|
||||
res => {
|
||||
|
||||
api.requests[method.toLowerCase()](action, data).then(
|
||||
(res) => {
|
||||
// If prop handleAjaxResponse is passed, pass it the response
|
||||
this.props.handleAjaxResponse && this.props.handleAjaxResponse(res);
|
||||
if (handleAjaxResponse && typeof handleAjaxResponse === 'function') handleAjaxResponse(res);
|
||||
|
||||
// Provide form data to the redirected page
|
||||
if (this.props.redirect) {
|
||||
this.props.history.push(this.props.redirect, data);
|
||||
if (redirect) {
|
||||
history.push(redirect, data);
|
||||
} else {
|
||||
this.setState({ processing: false });
|
||||
this.props.addStatus({
|
||||
setProcessing(false);
|
||||
addStatus({
|
||||
message: res.message,
|
||||
type: 'success'
|
||||
})
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
},
|
||||
error => {
|
||||
(error) => {
|
||||
console.log(error);
|
||||
this.setState({ processing: false });
|
||||
this.props.addStatus({
|
||||
setProcessing(false);
|
||||
addStatus({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
type: 'error',
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// If valid and not AJAX submit as usual
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form
|
||||
noValidate
|
||||
onSubmit={submit}
|
||||
method={method}
|
||||
action={action}
|
||||
className={className}
|
||||
>
|
||||
<FormContext.Provider value={{
|
||||
setValue,
|
||||
fields,
|
||||
processing,
|
||||
submitted,
|
||||
}}
|
||||
>
|
||||
<HiddenInput
|
||||
name="locale"
|
||||
valueOverride={locale}
|
||||
/>
|
||||
{children}
|
||||
</FormContext.Provider>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
noValidate
|
||||
onSubmit={this.submit}
|
||||
method={this.props.method}
|
||||
action={this.props.action}
|
||||
className={this.props.className}>
|
||||
<FormContext.Provider value={{
|
||||
setValue: this.setValue.bind(this),
|
||||
fields: this.state.fields,
|
||||
processing: this.state.processing,
|
||||
submitted: this.state.submitted
|
||||
}}>
|
||||
<HiddenInput
|
||||
name="locale"
|
||||
valueOverride={this.props.searchParams.locale} />
|
||||
{this.props.children}
|
||||
</FormContext.Provider>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
Form.defaultProps = {
|
||||
redirect: '',
|
||||
onSubmit: null,
|
||||
ajax: true,
|
||||
method: 'POST',
|
||||
action: '',
|
||||
handleAjaxResponse: false,
|
||||
className: '',
|
||||
};
|
||||
|
||||
export default withRouter(connect(mapState, mapDispatch)(Form));
|
||||
Form.propTypes = {
|
||||
onSubmit: PropTypes.func,
|
||||
ajax: PropTypes.bool,
|
||||
method: PropTypes.oneOf(['post', 'POST', 'get', 'GET', 'put', 'PUT', 'delete', 'DELETE']),
|
||||
action: PropTypes.string,
|
||||
handleAjaxResponse: PropTypes.func,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
className: PropTypes.string,
|
||||
redirect: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Form;
|
||||
|
||||
|
Before Width: | Height: | Size: 943 B After Width: | Height: | Size: 943 B |
@@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { FormContext } from '../Form';
|
||||
import FormContext from '../Form/Context';
|
||||
import Button from '../../controls/Button';
|
||||
|
||||
import './index.scss';
|
||||
@@ -16,13 +16,17 @@ class FormSubmit extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const ContextFormSubmit = props => {
|
||||
const ContextFormSubmit = (props) => {
|
||||
return (
|
||||
<FormContext.Consumer>
|
||||
{context => <FormSubmit {...props} context={context} />}
|
||||
{context => (
|
||||
<FormSubmit
|
||||
{...props}
|
||||
context={context}
|
||||
/>
|
||||
)}
|
||||
</FormContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContextFormSubmit;
|
||||
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { SearchParamsProvider } from './utilities/SearchParams';
|
||||
import { LocaleProvider } from './utilities/Locale';
|
||||
import { StatusListProvider } from './modules/Status';
|
||||
import Routes from './Routes';
|
||||
import store from '../store';
|
||||
import MeasureWindow from './utilities/MeasureWindow';
|
||||
import MeasureScroll from './utilities/MeasureScroll';
|
||||
import SetLocale from './utilities/SetLocale';
|
||||
import SetSearchParams from './utilities/SetSearchParams';
|
||||
|
||||
import '../scss/app.scss';
|
||||
|
||||
const Index = () => {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<Fragment>
|
||||
<MeasureScroll />
|
||||
<MeasureWindow />
|
||||
<SetLocale />
|
||||
<SetSearchParams />
|
||||
<Routes />
|
||||
</Fragment>
|
||||
</Router>
|
||||
</Provider>
|
||||
<Router>
|
||||
<SearchParamsProvider>
|
||||
<LocaleProvider>
|
||||
<StatusListProvider>
|
||||
<Routes />
|
||||
</StatusListProvider>
|
||||
</LocaleProvider>
|
||||
</SearchParamsProvider>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.default-template {
|
||||
@include default-template-width;
|
||||
padding-top: rem(1);
|
||||
padding-top: base(1);
|
||||
|
||||
.eyebrow {
|
||||
@include m;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
section.section {
|
||||
@extend %shadow;
|
||||
margin: rem(1) rem(.5);
|
||||
margin: base(1) base(.5);
|
||||
|
||||
header,
|
||||
.content {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: rem(6);
|
||||
padding: rem(1);
|
||||
width: base(6);
|
||||
padding: base(1);
|
||||
|
||||
.icon-wrap {
|
||||
margin: 0 0 rem(.5);
|
||||
margin: 0 0 base(.5);
|
||||
|
||||
> * {
|
||||
height: $base;
|
||||
@@ -21,26 +21,26 @@
|
||||
}
|
||||
|
||||
nav {
|
||||
margin: rem(.25) 0 $base;
|
||||
margin: base(.25) 0 $base;
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: rem(.33) 0;
|
||||
padding: base(.33) 0;
|
||||
border-bottom: 0;
|
||||
|
||||
svg {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: - rem(.5);
|
||||
left: - base(.5);
|
||||
transform: translateY(-50%);
|
||||
width: rem(.3);
|
||||
height: rem(.3);
|
||||
width: base(.3);
|
||||
height: base(.3);
|
||||
}
|
||||
|
||||
&.active {
|
||||
padding-left: rem(.6);
|
||||
padding-left: base(.6);
|
||||
|
||||
svg {
|
||||
opacity: 1;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
.sticky {
|
||||
z-index: 10;
|
||||
padding-top: rem(.75);
|
||||
padding-bottom: rem(.75);
|
||||
padding-top: base(.75);
|
||||
padding-bottom: base(.75);
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
@@ -11,7 +11,7 @@ table {
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: rem(.5);
|
||||
padding: base(.5);
|
||||
}
|
||||
|
||||
tbody {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 rem(.5) 0 0;
|
||||
margin: 0 base(.5) 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
svg {
|
||||
transform: rotate(90deg);
|
||||
width: rem(.25);
|
||||
height: rem(.25);
|
||||
margin-right: rem(.375);
|
||||
width: base(.25);
|
||||
height: base(.25);
|
||||
margin-right: base(.375);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -1,40 +1,79 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Close } from 'payload/components';
|
||||
import React, { useState, createContext, useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Close from '../../forms/Submit/graphics/Close';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const mapState = state => ({
|
||||
status: state.common.status
|
||||
})
|
||||
const Context = createContext({});
|
||||
|
||||
const mapDispatch = dispatch => ({
|
||||
addStatus: status => dispatch({ type: 'ADD_STATUS', payload: status }),
|
||||
removeStatus: i => dispatch({ type: 'REMOVE_STATUS', payload: i })
|
||||
})
|
||||
const StatusListProvider = ({ children }) => {
|
||||
const [statusList, setStatus] = useState([]);
|
||||
|
||||
const Status = props => {
|
||||
if (props.status.length > 0) {
|
||||
return (
|
||||
<Context.Provider value={{
|
||||
statusList,
|
||||
removeStatus: (i) => {
|
||||
const newStatusList = [...statusList];
|
||||
newStatusList.splice(i, 1);
|
||||
setStatus(newStatusList);
|
||||
},
|
||||
addStatus: status => [
|
||||
...statusList,
|
||||
status,
|
||||
],
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
StatusListProvider.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
const useStatusList = () => useContext(Context);
|
||||
|
||||
const StatusList = () => {
|
||||
const { statusList, removeStatus } = useStatusList();
|
||||
|
||||
if (statusList.length > 0) {
|
||||
return (
|
||||
<ul className="status">
|
||||
{props.status.map((status, i) => {
|
||||
{statusList.map((status, i) => {
|
||||
return (
|
||||
<li className={status.type} key={i}>
|
||||
<li
|
||||
className={status.type}
|
||||
key={i}
|
||||
>
|
||||
{status.message}
|
||||
<button className="close" onClick={e => {
|
||||
e.preventDefault();
|
||||
props.removeStatus(i)
|
||||
}}>
|
||||
<button
|
||||
type="button"
|
||||
className="close"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
removeStatus(i);
|
||||
}}
|
||||
>
|
||||
<Close />
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default connect(mapState, mapDispatch)(Status);
|
||||
export {
|
||||
StatusListProvider,
|
||||
StatusList,
|
||||
useStatusList,
|
||||
};
|
||||
|
||||
export default Context;
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
color: $black;
|
||||
font-weight: bold;
|
||||
border-radius: $radius-sm;
|
||||
padding: rem(.5);
|
||||
margin-bottom: rem(.5);
|
||||
padding: base(.5);
|
||||
margin-bottom: base(.5);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
svg {
|
||||
@include color-svg($black);
|
||||
width: rem(.35);
|
||||
height: rem(.35);
|
||||
width: base(.35);
|
||||
height: base(.35);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
}
|
||||
|
||||
a {
|
||||
margin-right: rem(.35);
|
||||
margin-right: base(.35);
|
||||
border: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
margin-left: rem(.35);
|
||||
width: rem(.25);
|
||||
height: rem(.25);
|
||||
margin-left: base(.35);
|
||||
width: base(.25);
|
||||
height: base(.25);
|
||||
}
|
||||
|
||||
label {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
padding-right: rem(1);
|
||||
padding-right: base(1);
|
||||
}
|
||||
|
||||
.controls {
|
||||
@@ -25,7 +25,7 @@
|
||||
}
|
||||
|
||||
> *:last-child {
|
||||
margin-left: rem(1);
|
||||
margin-left: base(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
right: - rem(1);
|
||||
right: - base(1);
|
||||
bottom: 0;
|
||||
left: - rem(1);
|
||||
left: - base(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0 rem(.4);
|
||||
padding: 0 base(.4);
|
||||
color: $black;
|
||||
line-height: rem(.8);
|
||||
line-height: base(.8);
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
top: rem(.7);
|
||||
top: base(.7);
|
||||
left: 50%;
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
|
||||
.upload-media {
|
||||
padding: rem(1);
|
||||
padding: base(1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
@@ -17,6 +17,6 @@
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: rem(.125) 0 0;
|
||||
margin: base(.125) 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
37
src/client/components/utilities/Locale/index.js
Normal file
37
src/client/components/utilities/Locale/index.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import config from 'payload-config';
|
||||
import PropTypes from 'prop-types';
|
||||
import searchParamsContext from '../SearchParams';
|
||||
|
||||
const Context = createContext({});
|
||||
|
||||
export const LocaleProvider = ({ children }) => {
|
||||
const searchParams = useContext(searchParamsContext);
|
||||
|
||||
let activeLocale = null;
|
||||
|
||||
if (config.localization) {
|
||||
if (searchParams.locale && config.localization.locales.indexOf(searchParams.locale) > -1) {
|
||||
activeLocale = searchParams.locale;
|
||||
} else {
|
||||
activeLocale = (config.localization.defaultLocale);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Context.Provider value={activeLocale}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocale = () => useContext(Context);
|
||||
|
||||
LocaleProvider.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
export default Context;
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
scrollPercentage: state.common.scrollPercentage,
|
||||
scrollPos: state.common.scrollPos
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
updateScroll: (pos) => dispatch({ type: 'UPDATE_SCROLL', payload: pos }),
|
||||
updateScrollPercentage : (percentage) => dispatch({ type: 'UPDATE_SCROLL_PERCENTAGE', payload: percentage })
|
||||
});
|
||||
|
||||
class MeasureScroll extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
if ('scrollRestoration' in window.history) {
|
||||
window.history.scrollRestoration = 'manual';
|
||||
}
|
||||
|
||||
// Throttle scroll event
|
||||
let ticking = false;
|
||||
let latestKnownScrollY = 0;
|
||||
let scrollPercentage = 0;
|
||||
|
||||
this.updateScroll = () => {
|
||||
ticking = false;
|
||||
this.props.updateScroll(latestKnownScrollY);
|
||||
this.props.updateScrollPercentage(scrollPercentage);
|
||||
};
|
||||
|
||||
this.onScroll = () => {
|
||||
const roundedPercent = 100;
|
||||
const roundedDecimal = 2;
|
||||
latestKnownScrollY = window.pageYOffset;
|
||||
scrollPercentage = (latestKnownScrollY / (document.body.scrollHeight - window.innerHeight) * roundedPercent).toFixed(roundedDecimal);
|
||||
this.requestTick();
|
||||
};
|
||||
|
||||
this.requestTick = () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(this.updateScroll);
|
||||
}
|
||||
ticking = true;
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('scroll', this.onScroll, false);
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(MeasureScroll);
|
||||
@@ -1,55 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
windowWidth: state.common.windowWidth,
|
||||
windowHeight: state.common.windowHeight
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
setWindowSize: (size) => dispatch({ type: 'SET_WINDOW_SIZE', payload: size }),
|
||||
});
|
||||
|
||||
class MeasureWindow extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.setSize = this.setSize.bind(this);
|
||||
this.onResize = this.onResize.bind(this);
|
||||
}
|
||||
|
||||
setSize() {
|
||||
this.props.setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
});
|
||||
}
|
||||
|
||||
onResize() {
|
||||
// Only resize on screens larger than mobile
|
||||
// To avoid toolbars hiding and orientation change
|
||||
const mobileWidth = 450;
|
||||
|
||||
if (window.innerWidth > mobileWidth) {
|
||||
this.setSize();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
|
||||
window.addEventListener('orientationchange', () => {
|
||||
const delay = 500;
|
||||
setTimeout(() => {
|
||||
this.setSize();
|
||||
}, delay);
|
||||
});
|
||||
|
||||
this.setSize();
|
||||
}
|
||||
|
||||
render() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(MeasureWindow);
|
||||
30
src/client/components/utilities/SearchParams/index.js
Normal file
30
src/client/components/utilities/SearchParams/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import qs from 'qs';
|
||||
|
||||
const Context = createContext({});
|
||||
|
||||
export const SearchParamsProvider = ({ children }) => {
|
||||
const location = useLocation();
|
||||
|
||||
const params = qs.parse(
|
||||
location.search,
|
||||
{ ignoreQueryPrefix: true },
|
||||
);
|
||||
|
||||
return (
|
||||
<Context.Provider value={params}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
SearchParamsProvider.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
export default Context;
|
||||
@@ -1,51 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapState = state => ({
|
||||
config: state.common.config,
|
||||
searchParams: state.common.searchParams
|
||||
})
|
||||
|
||||
const mapDispatch = dispatch => ({
|
||||
setLocale: locale => dispatch({ type: 'SET_LOCALE', payload: locale })
|
||||
})
|
||||
|
||||
class SetLocale extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
init: false
|
||||
}
|
||||
}
|
||||
|
||||
setLocale = () => {
|
||||
const { searchParams, config, setLocale } = this.props;
|
||||
|
||||
if (searchParams && config.localization) {
|
||||
if (searchParams.locale && config.localization.locales.indexOf(searchParams.locale) > -1) {
|
||||
setLocale(searchParams.locale);
|
||||
} else if (!this.state.init) {
|
||||
setLocale(config.localization.defaultLocale);
|
||||
this.setState({ init: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setLocale();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.searchParams !== this.props.searchParams || prevProps.config !== this.props.config) {
|
||||
this.setLocale();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapState, mapDispatch)(SetLocale);
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Component } from 'react'
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import qs from 'qs';
|
||||
|
||||
const mapDispatch = dispatch => ({
|
||||
setParams: params => dispatch({ type: 'SET_SEARCH_PARAMS', payload: params })
|
||||
})
|
||||
|
||||
class SetSearchParams extends Component {
|
||||
|
||||
setParams = () => {
|
||||
const params = qs.parse(
|
||||
this.props.location.search,
|
||||
{ ignoreQueryPrefix: true }
|
||||
);
|
||||
|
||||
this.props.setParams(params ? params : {});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setParams();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.location !== this.props.location) {
|
||||
this.setParams();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(connect(null, mapDispatch)(SetSearchParams));
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import Cookies from 'universal-cookie';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ContentBlock from '../../layout/ContentBlock';
|
||||
import Form from '../../forms/Form';
|
||||
@@ -10,25 +9,17 @@ import FormSubmit from '../../forms/Submit';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
windowHeight: state.common.windowHeight,
|
||||
});
|
||||
|
||||
const cookies = new Cookies();
|
||||
|
||||
const handleAjaxResponse = (res) => {
|
||||
cookies.set('token', res.token, { path: '/' });
|
||||
};
|
||||
|
||||
const Login = (props) => {
|
||||
const Logo = props.logo;
|
||||
const minHeight = props.windowHeight;
|
||||
|
||||
const Login = () => {
|
||||
return (
|
||||
<ContentBlock
|
||||
className="login"
|
||||
width="narrow"
|
||||
style={{ minHeight }}
|
||||
>
|
||||
<div className="wrap">
|
||||
<Form
|
||||
@@ -56,4 +47,4 @@ const Login = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(Login);
|
||||
export default Login;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@import '~payload/client/scss/styles';
|
||||
@import '../../../scss/styles';
|
||||
|
||||
.login {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
min-height: 100vh;
|
||||
|
||||
.logo-wrap {
|
||||
display: block;
|
||||
margin: 0 auto rem(1);
|
||||
margin: 0 auto base(1);
|
||||
max-width: 200px;
|
||||
|
||||
svg {
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
const defaultState = {
|
||||
scrollPos: 0,
|
||||
windowWidth: 1400,
|
||||
windowHeight: 900,
|
||||
viewWidth: false,
|
||||
viewHeight: false,
|
||||
stepNav: [],
|
||||
locale: null,
|
||||
config: {
|
||||
collections: {},
|
||||
localization: {
|
||||
locales: []
|
||||
},
|
||||
routes: {},
|
||||
},
|
||||
searchParams: {},
|
||||
status: []
|
||||
};
|
||||
|
||||
export default (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
|
||||
case 'UPDATE_SCROLL':
|
||||
|
||||
return {
|
||||
...state,
|
||||
scrollPos: action.payload
|
||||
};
|
||||
|
||||
case 'SET_WINDOW_SIZE':
|
||||
|
||||
return {
|
||||
...state,
|
||||
windowWidth: action.payload.width,
|
||||
windowHeight: action.payload.height
|
||||
};
|
||||
|
||||
case 'SET_VIEW_SIZE':
|
||||
|
||||
return {
|
||||
...state,
|
||||
viewWidth: action.payload.width,
|
||||
viewHeight: action.payload.height
|
||||
};
|
||||
|
||||
case 'SET_STEP_NAV':
|
||||
|
||||
return {
|
||||
...state,
|
||||
stepNav: action.payload
|
||||
};
|
||||
|
||||
case 'LOAD_CONFIG':
|
||||
|
||||
return {
|
||||
...state,
|
||||
config: action.payload
|
||||
};
|
||||
|
||||
case 'SET_LOCALE':
|
||||
return {
|
||||
...state,
|
||||
locale: action.payload
|
||||
}
|
||||
|
||||
case 'SET_SEARCH_PARAMS':
|
||||
return {
|
||||
...state,
|
||||
searchParams: action.payload
|
||||
}
|
||||
|
||||
case 'ADD_STATUS':
|
||||
return {
|
||||
...state,
|
||||
status: [
|
||||
action.payload,
|
||||
...state.status
|
||||
]
|
||||
};
|
||||
|
||||
case 'REMOVE_STATUS': {
|
||||
const newStatus = [...state.status];
|
||||
newStatus.splice(action.payload, 1);
|
||||
return {
|
||||
...state,
|
||||
status: newStatus
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
//
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
@@ -24,17 +24,17 @@ body {
|
||||
|
||||
html {
|
||||
font-size: $body;
|
||||
line-height: rem(1);
|
||||
line-height: base(1);
|
||||
font-size: 20px;
|
||||
|
||||
@include mid-break {
|
||||
font-size: 18px;
|
||||
line-height: rem(1);
|
||||
line-height: base(1);
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
font-size: 16px;
|
||||
line-height: rem(.8)
|
||||
line-height: base(.8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ h5 {
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 rem(.5);
|
||||
margin: 0 0 base(.5);
|
||||
}
|
||||
|
||||
ul {
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
background: white;
|
||||
color: $black;
|
||||
border-radius: 0;
|
||||
font-size: rem(.55);
|
||||
height: rem(1.75);
|
||||
line-height: rem(1.75);
|
||||
padding: 0 rem(.75);
|
||||
font-size: base(.55);
|
||||
height: base(1.75);
|
||||
line-height: base(1.75);
|
||||
padding: 0 base(.75);
|
||||
-webkit-appearance: none;
|
||||
|
||||
&::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
@@ -43,6 +43,6 @@
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(.5);
|
||||
margin-bottom: base(.5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/////////////////////////////
|
||||
|
||||
// Gutter
|
||||
$gutter : rem(.5);
|
||||
$gutter : base(.5);
|
||||
|
||||
/////////////////////////////
|
||||
// ROWS
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
@mixin default-template-width {
|
||||
padding-left: $base;
|
||||
padding-right: $base;
|
||||
margin-left: rem(6);
|
||||
width: calc(100% - #{rem(6)});
|
||||
margin-left: base(6);
|
||||
width: calc(100% - #{base(6)});
|
||||
|
||||
.wrap {
|
||||
max-width: $content-width;
|
||||
@@ -25,19 +25,19 @@
|
||||
padding: $base;
|
||||
|
||||
@include mid-break {
|
||||
padding: rem(.75);
|
||||
padding: base(.75);
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
padding: rem(.5);
|
||||
padding: base(.5);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin pad-x2 {
|
||||
padding: rem(2) rem(2) rem(1);
|
||||
padding: base(2) base(2) base(1);
|
||||
|
||||
@include mid-break {
|
||||
padding: rem(1) rem(1) 0;
|
||||
padding: base(1) base(1) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
padding-top: $base;
|
||||
|
||||
@include mid-break {
|
||||
padding-top: rem(.5);
|
||||
padding-top: base(.5);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin pad-vert-x2 {
|
||||
padding-top: rem(2);
|
||||
padding-top: base(2);
|
||||
padding-bottom: $base;
|
||||
|
||||
@include mid-break {
|
||||
@@ -64,21 +64,21 @@
|
||||
}
|
||||
|
||||
@mixin pad-vert-x3 {
|
||||
padding-top: rem(3);
|
||||
padding-bottom: rem(2);
|
||||
padding-top: base(3);
|
||||
padding-bottom: base(2);
|
||||
|
||||
@include mid-break {
|
||||
padding-top: rem(2);
|
||||
padding-top: base(2);
|
||||
padding-bottom: $base;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin pad-vert-x4 {
|
||||
padding-top: rem(4);
|
||||
padding-bottom: rem(3);
|
||||
padding-top: base(4);
|
||||
padding-bottom: base(3);
|
||||
|
||||
@include mid-break {
|
||||
padding-top: rem(2);
|
||||
padding-top: base(2);
|
||||
padding-bottom: $base;
|
||||
}
|
||||
}
|
||||
@@ -91,42 +91,42 @@
|
||||
margin-bottom: $base;
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(.75);
|
||||
margin-bottom: base(.75);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin m-x2 {
|
||||
margin-bottom: rem(2);
|
||||
margin-bottom: base(2);
|
||||
|
||||
@include mid-break {
|
||||
margin-bottom: $base;
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(.75);
|
||||
margin-bottom: base(.75);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin m-x3 {
|
||||
margin-bottom: rem(3);
|
||||
margin-bottom: base(3);
|
||||
|
||||
@include mid-break {
|
||||
margin-bottom: rem(2);
|
||||
margin-bottom: base(2);
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(1);
|
||||
margin-bottom: base(1);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin m-x4 {
|
||||
margin-bottom: rem(4);
|
||||
margin-bottom: base(4);
|
||||
|
||||
@include mid-break {
|
||||
margin-bottom: rem(3);
|
||||
margin-bottom: base(3);
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
margin-bottom: rem(2);
|
||||
margin-bottom: base(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,63 +12,63 @@
|
||||
}
|
||||
|
||||
%jumbo {
|
||||
font-size: rem(2.5);
|
||||
font-size: base(2.5);
|
||||
line-height: 1;
|
||||
margin: 0 0 rem(2);
|
||||
margin: 0 0 base(2);
|
||||
}
|
||||
|
||||
%h1 {
|
||||
margin: 0 0 rem(1);
|
||||
font-size: rem(1);
|
||||
line-height: rem(1);
|
||||
margin: 0 0 base(1);
|
||||
font-size: base(1);
|
||||
line-height: base(1);
|
||||
|
||||
@include small-break {
|
||||
letter-spacing: rem(0);
|
||||
font-size: rem(1.25);
|
||||
line-height: rem(1.25);
|
||||
letter-spacing: base(0);
|
||||
font-size: base(1.25);
|
||||
line-height: base(1.25);
|
||||
}
|
||||
}
|
||||
|
||||
%h2 {
|
||||
margin: 0 0 rem(1);
|
||||
font-size: rem(.7);
|
||||
line-height: rem(.75);
|
||||
margin: 0 0 base(1);
|
||||
font-size: base(.7);
|
||||
line-height: base(.75);
|
||||
letter-spacing: 0;
|
||||
|
||||
@include small-break {
|
||||
font-size: rem(.85);
|
||||
line-height: rem(.85);
|
||||
font-size: base(.85);
|
||||
line-height: base(.85);
|
||||
}
|
||||
}
|
||||
|
||||
%h3 {
|
||||
margin: 0 0 rem(1);
|
||||
font-size: rem(1);
|
||||
margin: 0 0 base(1);
|
||||
font-size: base(1);
|
||||
line-height: 1.25;
|
||||
font-weight: 500;
|
||||
|
||||
@include small-break {
|
||||
font-size: rem(.65);
|
||||
line-height: rem(.75);
|
||||
font-size: base(.65);
|
||||
line-height: base(.75);
|
||||
}
|
||||
}
|
||||
|
||||
%h4 {
|
||||
margin: 0 0 $base;
|
||||
font-size: rem(.75);
|
||||
font-size: base(.75);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
%h5 {
|
||||
margin: 0;
|
||||
font-size: rem(.5);
|
||||
font-size: base(.5);
|
||||
line-height: 1.5;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
%small {
|
||||
margin: 0;
|
||||
font-size: rem(.4);
|
||||
font-size: base(.4);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@@ -78,35 +78,35 @@
|
||||
|
||||
%uppercase-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: rem(.1);
|
||||
font-size: rem(.3);
|
||||
letter-spacing: base(.1);
|
||||
font-size: base(.3);
|
||||
font-family: $font-label;
|
||||
-webkit-font-smoothing: auto;
|
||||
|
||||
@include mid-break {
|
||||
font-size: rem(.31);
|
||||
letter-spacing: rem(.05);
|
||||
font-size: base(.31);
|
||||
letter-spacing: base(.05);
|
||||
}
|
||||
}
|
||||
|
||||
%large-body {
|
||||
font-size: rem(.6);
|
||||
line-height: rem(1);
|
||||
letter-spacing: rem(.02);
|
||||
font-size: base(.6);
|
||||
line-height: base(1);
|
||||
letter-spacing: base(.02);
|
||||
|
||||
@include mid-break {
|
||||
font-size: rem(.7);
|
||||
line-height: rem(1);
|
||||
font-size: base(.7);
|
||||
line-height: base(1);
|
||||
}
|
||||
|
||||
@include small-break {
|
||||
font-size: rem(.55);
|
||||
line-height: rem(.75);
|
||||
font-size: base(.55);
|
||||
line-height: base(.75);
|
||||
}
|
||||
}
|
||||
|
||||
%code {
|
||||
font-size: rem(.4);
|
||||
font-size: base(.4);
|
||||
color: $gray;
|
||||
|
||||
span {
|
||||
|
||||
@@ -18,7 +18,7 @@ $body : 18px;
|
||||
$base-px : 36px;
|
||||
$base : ($base-px / $body) + rem; // This computes to 36px in rem
|
||||
|
||||
@function rem($multiplier) {
|
||||
@function base($multiplier) {
|
||||
@return ($base-px / $body) * $multiplier + rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { createStore, combineReducers } from 'redux';
|
||||
import common from './reducers/common';
|
||||
|
||||
const reducer = combineReducers({
|
||||
common
|
||||
});
|
||||
|
||||
const store = createStore(reducer);
|
||||
|
||||
export default store;
|
||||
Reference in New Issue
Block a user