Merge pull request #4229 from strapi/update/plugin-generators

Add front-end files in the plugin generator
This commit is contained in:
Alexandre BODIN 2019-10-15 12:44:10 +02:00 committed by GitHub
commit b121a0da4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 200 additions and 733 deletions

View File

@ -9,10 +9,13 @@ const Wrapper = styled.div`
width: 100%;
line-height: 5.8rem;
z-index: 999;
> button {
> button,
> button.btn {
position: relative;
z-index: 9;
width: 100%;
padding-right: 20px;
background: transparent;
background: white;
border: none;
border-radius: 0;
color: #333740;
@ -27,6 +30,7 @@ const Wrapper = styled.div`
&:active {
color: #333740;
background-color: #fafafb !important;
z-index: 9;
}
> i {
@ -57,6 +61,8 @@ const Wrapper = styled.div`
}
.dropDownContent {
z-index: 8;
top: -3px !important;
left: auto !important;
min-width: 100% !important;
margin: 0 !important;
@ -72,7 +78,7 @@ const Wrapper = styled.div`
&:before {
content: '';
position: absolute;
top: -3px;
top: 0;
left: -1px;
width: calc(100% + 1px);
height: 3px;
@ -80,21 +86,16 @@ const Wrapper = styled.div`
}
> button {
height: 40px;
height: 54px;
padding: 0px 15px;
line-height: 40px;
&:hover,
&:focus,
&:active {
background-color: #fafafb !important;
border-radius: 0px;
cursor: pointer;
outline: 0;
}
}
> button {
height: 44px;
line-height: 48px;
&:hover,
&:active {
color: #333740;

View File

@ -10,38 +10,45 @@ const chokidar = require('chokidar');
const getPkgPath = name =>
path.dirname(require.resolve(`${name}/package.json`));
async function createPluginsJs(plugins, dest) {
async function createPluginsJs(plugins, localPlugins, dest) {
const content = `
const injectReducer = require('./utils/injectReducer').default;
const injectSaga = require('./utils/injectSaga').default;
const useInjectReducer = require('./utils/injectReducer').useInjectReducer;
const useInjectSaga = require('./utils/injectSaga').useInjectSaga;
const { languages } = require('./i18n');
const injectReducer = require('./utils/injectReducer').default;
const injectSaga = require('./utils/injectSaga').default;
const useInjectReducer = require('./utils/injectReducer').useInjectReducer;
const useInjectSaga = require('./utils/injectSaga').useInjectSaga;
const { languages } = require('./i18n');
window.strapi = Object.assign(window.strapi || {}, {
node: MODE || 'host',
backendURL: BACKEND_URL === '/' ? window.location.origin : BACKEND_URL,
languages,
currentLanguage:
window.localStorage.getItem('strapi-admin-language') ||
window.navigator.language ||
window.navigator.userLanguage ||
'en',
injectReducer,
injectSaga,
useInjectReducer,
useInjectSaga,
});
window.strapi = Object.assign(window.strapi || {}, {
node: MODE || 'host',
backendURL: BACKEND_URL === '/' ? window.location.origin : BACKEND_URL,
languages,
currentLanguage:
window.localStorage.getItem('strapi-admin-language') ||
window.navigator.language ||
window.navigator.userLanguage ||
'en',
injectReducer,
injectSaga,
useInjectReducer,
useInjectSaga,
});
module.exports = {
${plugins
.map(name => {
const shortName = name.replace(/^strapi-plugin-/i, '');
const req = `require('../../plugins/${name}/admin/src').default`;
return `'${shortName}': ${req}`;
})
.join(',\n')}
}
module.exports = {
${plugins
.map(name => {
const shortName = name.replace(/^strapi-plugin-/i, '');
const req = `require('../../plugins/${name}/admin/src').default`;
return `'${shortName}': ${req},`;
})
.join('\n')}
${localPlugins
.map(name => {
const shortName = name.replace(/^strapi-plugin-/i, '');
const req = `require('../../../plugins/${name}/admin/src').default`;
return `'${shortName}': ${req}`;
})
.join(',\n')}
}
`;
return fs.writeFile(
@ -98,6 +105,14 @@ async function createCacheDir(dir) {
fs.existsSync(path.resolve(getPkgPath(dep), 'admin', 'src', 'index.js'))
);
const localPluginsToCopy = fs
.readdirSync(path.join(dir, 'plugins'))
.filter(plugin =>
fs.existsSync(
path.resolve(dir, 'plugins', plugin, 'admin', 'src', 'index.js')
)
);
// TODO: add logic to avoid copying files if not necessary
// create .cache dir
@ -110,7 +125,7 @@ async function createCacheDir(dir) {
await Promise.all(pluginsToCopy.map(name => copyPlugin(name, cacheDir)));
// create plugins.js with plugins requires
await createPluginsJs(pluginsToCopy, cacheDir);
await createPluginsJs(pluginsToCopy, localPluginsToCopy, cacheDir);
// override admin code with user customizations
if (fs.pathExistsSync(path.join(dir, 'admin'))) {

View File

@ -1,5 +0,0 @@
/*
*
* App actions
*
*/

View File

@ -1,5 +0,0 @@
/*
*
* App constants
*
*/

View File

@ -6,66 +6,22 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { Switch, Route } from 'react-router-dom';
import { bindActionCreators, compose } from 'redux';
import { NotFound } from 'strapi-helper-plugin';
// Utils
import pluginId from 'pluginId';
import pluginId from '../../pluginId';
// Containers
import HomePage from 'containers/HomePage';
import NotFoundPage from 'containers/NotFoundPage';
// When you're done studying the ExamplePage container, remove the following line and delete the ExamplePage container
import ExamplePage from 'containers/ExamplePage';
import HomePage from '../HomePage';
import reducer from './reducer';
class App extends React.Component {
// When you're done studying the ExamplePage container, remove the following lines and delete the ExamplePage container
componentDidMount() {
this.props.history.push(`/plugins/${pluginId}/example`);
}
render() {
return (
<div className={pluginId}>
<Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
{/* When you're done studying the ExamplePage container, remove the following line and delete the ExamplePage container */}
<Route path={`/plugins/${pluginId}/example`} component={ExamplePage} exact />
<Route component={NotFoundPage} />
</Switch>
</div>
);
}
}
App.contextTypes = {
plugins: PropTypes.object,
updatePlugin: PropTypes.func,
};
App.propTypes = {
history: PropTypes.object.isRequired,
};
export function mapDispatchToProps(dispatch) {
return bindActionCreators(
{},
dispatch,
const App = () => {
return (
<div className={pluginId}>
<Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
<Route component={NotFound} />
</Switch>
</div>
);
}
};
const mapStateToProps = createStructuredSelector({});
// Wrap the component to inject dispatch and state into it
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = strapi.injectReducer({ key: 'global', reducer, pluginId });
export default compose(
withReducer,
withConnect,
)(App);
export default App;

View File

@ -1,18 +0,0 @@
/*
*
* App reducer
*
*/
import { fromJS } from 'immutable';
const initialState = fromJS({});
function appReducer(state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
export default appReducer;

View File

@ -1,10 +0,0 @@
// import { createSelector } from 'reselect';
// import pluginId from 'pluginId';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get(`${pluginId}_global`);
export {};

View File

@ -1,20 +0,0 @@
/*
*
* ExamplePage actions
*
*/
import { LOAD_DATA, LOADED_DATA } from './constants';
export function loadData() {
return {
type: LOAD_DATA,
};
}
export function loadedData(data) {
return {
type: LOADED_DATA,
data,
};
}

View File

@ -1,10 +0,0 @@
/*
*
* ExamplePage constants
*
*/
import pluginId from 'pluginId';
export const LOAD_DATA = `${pluginId}/ExamplePage/LOAD_DATA`;
export const LOADED_DATA = `${pluginId}/ExamplePage/LOADED_DATA`;

View File

@ -1,98 +0,0 @@
/*
*
* ExamplePage
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import pluginId from 'pluginId';
import Button from 'components/Button';
import styles from './styles.scss';
import { loadData } from './actions';
import { makeSelectLoading, makeSelectData } from './selectors';
import reducer from './reducer';
import saga from './saga';
export class ExamplePage extends React.Component {
generateDataBlock() {
if (this.props.data) {
const items = this.props.data.map((item, i) => <li key={i}>{item}</li>);
return (
<div>
<p>Data:</p>
<ul>{items}</ul>
</div>
);
}
return;
}
render() {
console.log('Don\'t forget to delete the ExampleContainer when you\'re done studying it');
// Generate the data block
const dataBlock = this.generateDataBlock();
return (
<div className={styles.examplePage}>
<div className="row">
<div className="col-md-12">
<p>This is an example of a fake API call.</p>
<p>Loading: {this.props.loading ? 'yes' : 'no'}.</p>
{dataBlock}
<Button
label={this.props.loading ? 'Loading...' : 'Submit'}
disabled={this.props.loading}
onClick={this.props.loadData}
primary
/>
</div>
</div>
</div>
);
}
}
ExamplePage.contextTypes = {
router: PropTypes.object,
};
ExamplePage.propTypes = {
data: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.object,
]).isRequired,
loadData: PropTypes.func.isRequired,
loading: PropTypes.bool.isRequired,
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
loadData,
},
dispatch,
);
}
const mapStateToProps = createStructuredSelector({
loading: makeSelectLoading(),
data: makeSelectData(),
});
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = strapi.injectReducer({ key: 'examplePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'examplePage', saga, pluginId });
export default compose(
withReducer,
withSaga,
withConnect,
)(injectIntl(ExamplePage));

View File

@ -1,27 +0,0 @@
/*
*
* ExamplePage reducer
*
*/
import { fromJS } from 'immutable';
import { LOAD_DATA, LOADED_DATA } from './constants';
const initialState = fromJS({
loading: false,
data: false,
});
function examplePageReducer(state = initialState, action) {
switch (action.type) {
case LOAD_DATA:
return state.set('loading', true);
case LOADED_DATA:
return state.set('loading', false).set('data', fromJS(action.data));
default:
return state;
}
}
export default examplePageReducer;

View File

@ -1,34 +0,0 @@
/* eslint-disable */
import { LOCATION_CHANGE } from 'react-router-redux';
import { takeLatest, put, fork, take, cancel } from 'redux-saga/effects';
import { loadedData } from './actions';
import { LOAD_DATA } from './constants';
export function* loadData() {
// Fake API request delay
yield new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
// Generate a random array
const data = Array(4)
.fill(0)
.map(() => Math.floor(Math.random() * 100));
yield put(loadedData(data));
}
// Individual exports for testing
export function* defaultSaga() {
const loadDataWatcher = yield fork(takeLatest, LOAD_DATA, loadData);
// Suspend execution until location changes
yield take(LOCATION_CHANGE);
yield cancel(loadDataWatcher);
}
// All sagas to be loaded
export default defaultSaga;

View File

@ -1,25 +0,0 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the examplePage state domain
*/
const selectExamplePageDomain = () => state => state.get(`${pluginId}_examplePage`);
/**
* Default selector used by HomePage
*/
const makeSelectLoading = () =>
createSelector(
selectExamplePageDomain(),
substate => substate.get('loading'),
);
const makeSelectData = () =>
createSelector(
selectExamplePageDomain(),
substate => substate.get('data'),
);
export { makeSelectLoading, makeSelectData };

View File

@ -1,13 +0,0 @@
/*
*
* HomePage actions
*
*/
import { DEFAULT_ACTION } from './constants';
export function defaultAction() {
return {
type: DEFAULT_ACTION,
};
}

View File

@ -1,9 +0,0 @@
/*
*
* HomePage constants
*
*/
import pluginId from 'pluginId';
export const DEFAULT_ACTION = `${pluginId}/HomePage/DEFAULT_ACTION`;

View File

@ -4,60 +4,17 @@
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import pluginId from 'pluginId';
import React, { memo } from 'react';
// import PropTypes from 'prop-types';
import pluginId from '../../pluginId';
// Selectors
import selectHomePage from './selectors';
// Styles
import styles from './styles.scss';
import reducer from './reducer';
import saga from './saga';
export class HomePage extends React.Component {
render() {
return (
<div className={styles.homePage}>
</div>
);
}
}
HomePage.contextTypes = {
router: PropTypes.object,
};
HomePage.propTypes = {
// homePage: PropTypes.object,
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
// Your actions here
},
dispatch,
const HomePage = () => {
return (
<div>
<h1>{pluginId}&apos;s HomePage</h1>
<p>Happy coding</p>
</div>
);
}
};
const mapStateToProps = createStructuredSelector({
homePage: selectHomePage(),
});
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,
withSaga,
withConnect,
)(injectIntl(HomePage));
export default memo(HomePage);

View File

@ -1,22 +0,0 @@
/*
*
* HomePage reducer
*
*/
import { fromJS } from 'immutable';
import { DEFAULT_ACTION } from './constants';
const initialState = fromJS({});
function homePageReducer(state = initialState, action) {
switch (action.type) {
case DEFAULT_ACTION:
return state;
default:
return state;
}
}
export default homePageReducer;

View File

@ -1,9 +0,0 @@
// import { LOCATION_CHANGE } from 'react-router-redux';
// import { takeLatest, put, fork, take, cancel } from 'redux-saga/effects';
// Individual exports for testing
export function* defaultSaga() {
}
// All sagas to be loaded
export default defaultSaga;

View File

@ -1,18 +0,0 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the homePage state domain
*/
const selectHomePageDomain = () => state => state.get(`${pluginId}_homePage`);
/**
* Default selector used by HomePage
*/
const selectHomePage = () =>
createSelector(
selectHomePageDomain(),
substate => substate.toJS(),
);
export default selectHomePage;

View File

@ -4,21 +4,20 @@
*
*/
import React from 'react';
import { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import pluginId from '../../pluginId';
class Initializer extends React.PureComponent {
// eslint-disable-line react/prefer-stateless-function
componentDidMount() {
// Emit the event 'pluginReady'
this.props.updatePlugin(pluginId, 'isReady', true);
}
const Initializer = ({ updatePlugin }) => {
const ref = useRef();
ref.current = updatePlugin;
render() {
return null;
}
}
useEffect(() => {
ref.current(pluginId, 'isReady', true);
}, []);
return null;
};
Initializer.propTypes = {
updatePlugin: PropTypes.func.isRequired,

View File

@ -1,25 +0,0 @@
// import React from 'react';
// import { mount, shallow } from 'enzyme';
// import pluginId from '../../pluginId';
// import Initializer from '../index';
describe('<Initializer />', () => {
// it('Should not crash', () => {
// const updatePlugin = jest.fn();
// const renderedComponent = shallow(<Initializer updatePlugin={updatePlugin} />);
// expect(renderedComponent.children()).toHaveLength(0);
// });
// it('should call the updatePlugin props when mounted', () => {
// const updatePlugin = jest.fn();
// const wrapper = mount(<Initializer updatePlugin={updatePlugin} />);
// expect(wrapper.prop('updatePlugin')).toHaveBeenCalledWith(pluginId, 'isReady', true);
// });
it('should have unit tests specified', () => {
expect(true).toBe(true);
});
});

View File

@ -1,20 +0,0 @@
/**
* NotFoundPage
*
* This is the page we show when the user visits a url that doesn't have a route
*
* NOTE: while this component should technically be a stateless functional
* component (SFC), hot reloading does not currently support SFCs. If hot
* reloading is not a neccessity for you then you can refactor it and remove
* the linting exception.
*/
import React from 'react';
import NotFound from 'components/NotFound';
export default class NotFoundPage extends React.Component {
render() {
return <NotFound {...this.props} />;
}
}

View File

@ -0,0 +1,34 @@
import React from 'react';
import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import App from './containers/App';
import Initializer from './containers/Initializer';
import lifecycles from './lifecycles';
import trads from './translations';
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
function Comp(props) {
return <App {...props} />;
}
const plugin = {
blockerComponent: null,
blockerComponentProps: {},
description: pluginDescription,
icon: pluginPkg.strapi.icon,
id: pluginId,
initializer: Initializer,
injectedComponents: [],
isReady: false,
layout: null,
lifecycles,
leftMenuLinks: [],
leftMenuSections: [],
mainComponent: Comp,
name: pluginPkg.strapi.name,
preventComponentRendering: false,
trads,
};
export default plugin;

View File

@ -1,23 +1,3 @@
/*
*
* SET THE HOOKS TO ENABLE THE MAGIC OF STRAPI.
* -------------------------------------------
*
* Secure, customise and enhance your project by setting
* the hooks via this file.
*
*/
function lifecycles() {}
module.exports = function lifecycles() {
// Set hooks for the AdminPage container.
// Note: we don't need to specify the first argument because we already know what "willSecure" refers to.
this.setHooks({
didGetSecuredData: () => console.log('do something'),
});
// Set hooks for the App container of the Content Manager.
// Note: we have to specify the first argument to select a specific container which is located in a plugin, or not.
// this.setHooks('content-manager.App', {
// willSomething: () => { console.log("Do Something"); }
// });
};
export default lifecycles;

View File

@ -0,0 +1,35 @@
import ar from './ar.json';
import de from './de.json';
import en from './en.json';
import es from './es.json';
import fr from './fr.json';
import it from './it.json';
import ko from './ko.json';
import nl from './nl.json';
import pl from './pl.json';
import ptBR from './pt-BR.json';
import pt from './pt.json';
import ru from './ru.json';
import tr from './tr.json';
import zhHans from './zh-Hans.json';
import zh from './zh.json';
const trads = {
ar,
de,
en,
es,
fr,
it,
ko,
nl,
pl,
'pt-BR': ptBR,
pt,
ru,
tr,
'zh-Hans': zhHans,
zh,
};
export default trads;

View File

@ -56,6 +56,12 @@ module.exports = (scope, cb) => {
const pluginDir = path.resolve(scope.rootPath, 'plugins');
fs.ensureDirSync(pluginDir);
// Copy the admin files.
fs.copySync(
path.resolve(__dirname, '..', 'files'),
path.resolve(pluginDir, scope.humanizeId)
);
// Trigger callback with no error to proceed.
return cb.success();
};

View File

@ -4,17 +4,26 @@ import { Button } from 'reactstrap';
const StyledButtonSecondary = styled(Button)`
position: relative;
height: 3rem;
padding-left: 1.5rem;
padding-right: 1.5rem;
font-family: Lato;
border-radius: 3px;
padding-left: 1.5rem !important;
padding-right: 1.5rem !important;
cursor: pointer;
font-family: Lato;
color: #f64d0a;
border: 0.1rem solid #f64d0a;
border-radius: 3px;
background-color: transparent;
border: 0.1rem solid #f64d0a;
color: #f64d0a;
&:hover,
&:active {
color: #f64d0a;
&:active,
&.btn-secondary:not(:disabled):not(.disabled):active,
&.btn-secondary:not(:disabled):not(.disabled):focus,
&.btn-secondary:not(:disabled):not(.disabled):focus:active,
&.btn-secondary:hover {
color: #f64d0a !important;
background-color: white;
border: 0.1rem solid #f64d0a;
}

View File

@ -7,8 +7,8 @@ import colors from '../../assets/styles/colors';
const StyledButtonModalSuccess = styled(Button)`
position: relative;
height: 3rem;
padding-left: 1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem !important;
padding-right: 1.5rem !important;
font-family: Lato;
color: ${colors.green};
border: 0.1rem solid ${colors.green};
@ -32,8 +32,12 @@ const StyledButtonModalSuccess = styled(Button)`
background-position: center;
}
&:hover,
&:active {
color: ${colors.green};
&:active,
&.btn-secondary:not(:disabled):not(.disabled):active,
&.btn-secondary:not(:disabled):not(.disabled):focus,
&.btn-secondary:not(:disabled):not(.disabled):focus:active,
&.btn-secondary:hover {
color: ${colors.green} !important;
background-color: white;
border: 0.1rem solid ${colors.green};
}

View File

@ -31,11 +31,9 @@ const Wrapper = styled.div`
font-size: 1.3rem;
color: #333740 !important;
line-height: 1.6rem;
}
.linkActive {
z-index: 10;
&:not(:first-child, :last-child) {
&.linkActive {
z-index: 10;
background-color: #ffffff !important;
font-weight: bold;
text-decoration: none !important;
@ -44,30 +42,6 @@ const Wrapper = styled.div`
}
}
.linkActive:first-child {
background-color: #ffffff !important;
font-weight: bold;
text-decoration: none !important;
box-shadow: 0 0 2px rgba(#dbdbdb, 0.5);
border-top: 0.2rem solid #1c5de7;
}
.linkActive:last-child {
background-color: #ffffff !important;
font-weight: bold;
text-decoration: none !important;
box-shadow: 0 0 2px rgba(#dbdbdb, 0.5);
border-top: 0.2rem solid #1c5de7;
}
.linkActive:not(:first-child, :last-child) {
background-color: #ffffff !important;
font-weight: bold;
text-decoration: none !important;
box-shadow: 0 0 2px rgba(#dbdbdb, 0.5);
border-top: 0.2rem solid #1c5de7;
}
.linkText {
display: flex;
margin: auto;

View File

@ -39,6 +39,7 @@ const FormWrapper = styled.div`
padding-top: 27px;
padding-left: 20px;
padding-right: 20px;
padding-bottom: 8px;
border-top: 1px solid
${({ hasErrors, isOpen }) => {
if (hasErrors) {

View File

@ -1,143 +1,7 @@
import styled from 'styled-components';
const Wrapper = styled.div`
.modalHeader {
margin: 0 2.9rem;
padding: 1.4rem 0 2.8rem 0;
border-bottom: 1px solid #f6f6f6;
position: relative;
> button {
margin-right: -2.5rem !important;
color: #c3c5c8;
opacity: 1;
font-size: 1.8rem;
font-weight: 100;
z-index: 999;
&:hover,
&:focus {
color: #c3c5c8;
opacity: 1;
outline: 0 !important;
}
> span {
display: none;
}
&:before {
-webkit-font-smoothing: antialiased;
content: '\F00d';
font-family: 'FontAwesome';
font-weight: 400;
font-size: 1.2rem;
margin-right: 10px;
}
}
}
.modalBody {
padding: 2.2rem 1.4rem 0 1.4rem;
}
.modalFooter {
padding: 1.2rem 1rem 2.8rem 1rem;
border: none;
> button {
height: 3rem;
position: relative;
border-radius: 0.3rem;
text-transform: capitalize;
margin-right: 1.8rem;
cursor: pointer;
font-family: Lato;
&:focus {
outline: 0;
}
> i {
margin-right: 1.3rem;
}
&:hover {
&::after {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border-radius: 0.3rem;
content: '';
opacity: 0.1;
background: #ffffff;
}
}
&.primary {
width: 15rem;
height: 3rem;
margin-left: 1.9rem !important;
cursor: pointer;
font-family: Lato;
border: none !important;
font-family: Lato !important;
line-height: 1.6rem;
font-weight: 600;
border-radius: 3px;
background: linear-gradient(315deg, #0097f6 0%, #005eea 100%);
-webkit-font-smoothing: antialiased;
color: white !important;
&:hover,
&:active {
border: none !important;
background: linear-gradient(315deg, #0097f6 0%, #005eea 100%);
color: white;
}
&:focus {
outline: 0;
}
}
&.secondary {
position: relative;
min-width: 100px;
height: 3rem;
cursor: pointer;
background-color: transparent;
border: 0.1rem solid #f64d0a;
border-radius: 3px;
color: #f64d0a;
font-family: Lato;
&:hover,
&:active {
color: #f64d0a;
background-color: white;
border: 0.1rem solid #f64d0a;
}
}
}
}
padding-bottom: 20px;
`;
const Header = styled.div`
position: absolute;
top: 0;
width: 100%;
display: flex;
padding: 1.6rem 2.9rem 0 2.9rem;
font-size: 1.8rem;
font-weight: bold;
`;
const ProviderContainer = styled.div`
> div {
&:last-child {
> input {
&:disabled {
background-color: #fafafb !important;
}
}
}
}
`;
const Separator = styled.div`
width: 100%;
margin: 14px 15px 20px 15px;
border-bottom: 2px solid #f6f6f6;
`;
export { Header, ProviderContainer, Separator, Wrapper };
export { Wrapper };

View File

@ -272,7 +272,11 @@ class PopUpForm extends React.Component {
type={includes(value, 'object') ? 'text' : 'textarea'}
validations={{ required: true }}
value={get(values, value)}
inputStyle={!includes(value, 'object') ? { height: '16rem' } : {}}
inputStyle={
!includes(value, 'object')
? { height: '16rem', marginBottom: '-0.8rem' }
: {}
}
/>
))}
</>