Display menu in modelPage

This commit is contained in:
soupette 2019-03-06 18:50:52 +01:00
parent e2de03a862
commit b4b025cd17
17 changed files with 472 additions and 6 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
/**
*
* LeftMenu
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import styles from './styles.scss';
function LeftMenu({ children }) {
return (
<div className={cn(styles.pluginLeftMenu, 'col-md-3')}>
{children}
</div>
);
}
LeftMenu.defaultProps = {
children: null,
};
LeftMenu.propTypes = {
children: PropTypes.node,
};
export default LeftMenu;

View File

@ -0,0 +1,49 @@
.pluginLeftMenu { /* stylelint-disable */
min-height: calc(100vh - 6rem); // TODO should be a global variable
border-radius: 1px;
background-color: #F2F3F4;
box-shadow: inset 0 0 0.2rem 0 rgba(0,0,0,0.05);
padding-top: .4rem;
}
.pluginLeftMenuSection { /* stylelint-disable */
margin-top: 3.3rem;
> p {
-webkit-font-smoothing: antialiased;
margin: 0;
padding-left: 1.5rem;
line-height: 1.3rem;
color: #919BAE;
letter-spacing: 0.1rem;
font-family: Lato;
font-size: 1.1rem;
font-weight: bold;
text-transform: uppercase;
}
> ul {
margin: 1rem 0 0 0rem;
padding: 1rem 0 0 3rem;
font-size: 1.3rem;
color: #2D3138;
> li {
margin-right: .5rem;
margin-bottom: 1.8rem;
line-height: 1.8rem;
overflow-wrap: break-word;
> a {
text-decoration: none;
color: #1C8FE5;
}
}
}
}
.pluginLeftMenuLink { /* stylelint-disable */
color: #2D3138;
li:not(:first-child) {
margin-top: 0.2rem;
}
}

View File

@ -0,0 +1,17 @@
import React from 'react';
import { shallow } from 'enzyme';
import LeftMenu from '../index';
describe('<LeftMenu />', () => {
it('should not crash', () => {
shallow(<LeftMenu />);
});
it('should render a child if given', () => {
const Child = () => <div>I'm a child</div>;
const wrapper = shallow(<LeftMenu><Child /></LeftMenu>);
expect(wrapper.find(Child).exists()).toBe(true);
});
});

View File

@ -0,0 +1,49 @@
/**
*
* LeftMenuLink
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { NavLink } from 'react-router-dom';
import { startCase } from 'lodash';
import { FormattedMessage } from 'react-intl';
import styles from './styles.scss';
function LeftMenuLink({ icon, name, source, to }) {
return (
<li className={styles.leftMenuLink}>
<NavLink className={styles.link} to={to} activeClassName={styles.linkActive}>
<div>
<i className={`fa ${icon}`} />
</div>
<div className={styles.container}>
<span className={styles.linkSpan}>{startCase(name)}</span>
{!!source && (
<FormattedMessage id="content-type-builder.from">
{msg => <span id="from-wrapper" style={{ marginLeft: '1rem', fontStyle: 'italic', marginRight: '10px' }}>({msg}: {source})</span>}
</FormattedMessage>
)}
</div>
</NavLink>
</li>
);
}
LeftMenuLink.defaultProps = {
icon: null,
name: null,
source: null,
to: '',
};
LeftMenuLink.propTypes = {
icon: PropTypes.string,
name: PropTypes.string,
source: PropTypes.string,
to: PropTypes.string,
};
export default LeftMenuLink;

View File

@ -0,0 +1,83 @@
.leftMenuLink {
color: #2D3138;
}
li:not(:first-child) {
margin-top: 0.2rem;
}
.link {
display: flex;
margin-left: 2rem;
margin-right: .5rem;
padding-top: 1rem;
padding-left: 1rem;
min-height: 3.4rem;
color: #2C3138 !important;
text-decoration: none !important;
line-height: 1.6rem;
> div:first-child {
width: 1.3rem;
margin-right: 1rem;
font-size: 11px;
> i {
color: #666B74;
}
}
> span {
display: block;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.linkActive {
height: 3.4rem;
border-radius: 0.2rem;
background-color: #E9EAEB;;
font-weight: bold;
text-decoration: none;
color: #2D3138 !important;
> div {
> i {
color: #2D3138 !important
}
}
}
.liInnerContainer {
display: flex;
margin-left: 2rem;
margin-right: .5rem;
padding-top: 1rem;
padding-left: 1rem;
min-height: 3.4rem;
color: #1C8FE5 !important;
text-decoration: none !important;
line-height: 1.6rem;
cursor: pointer;
> div {
width: 1.3rem;
margin-right: 1rem;
}
}
.linkSpan {
display: block;
width: calc(100% - 95px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.container {
display: flex;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -0,0 +1,22 @@
import React from 'react';
import { shallow } from 'enzyme';
import { FormattedMessage } from 'react-intl';
import LeftMenuLink from '../index';
describe('<LeftMenuLink />', () => {
it('Should not crash', () => {
shallow(<LeftMenuLink />);
});
it('should add a span containing from:<source /> if a source prop is given', () => {
const renderedComponent = shallow(<LeftMenuLink to="" name="test" source="source" />);
const sourceInfo = renderedComponent.find(FormattedMessage);
expect(sourceInfo.exists()).toBe(true);
const insideCompo = shallow(sourceInfo.prop('children')());
expect(insideCompo.find('span').length).toBe(1);
});
});

View File

@ -0,0 +1,28 @@
/**
*
* LeftMenuSection
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import styles from './styles.scss';
function LeftMenuSection({ children }) {
return (
<div className={styles.leftMenuSection}>
{children}
</div>
);
}
LeftMenuSection.defaultProps = {
children: null,
};
LeftMenuSection.propTypes = {
children: PropTypes.node,
};
export default LeftMenuSection;

View File

@ -0,0 +1,10 @@
.leftMenuSection {
margin-top: 3.3rem;
> ul {
margin: 1rem 0 0 -1.5rem;
padding: 0;
// list-style: none;
font-size: 1.3rem;
}
}

View File

@ -0,0 +1,17 @@
import React from 'react';
import { shallow } from 'enzyme';
import LeftMenuSection from '../index';
describe('<LeftMenuSection />', () => {
it('should not crash', () => {
shallow(<LeftMenuSection />);
});
it('should render a child if given', () => {
const Child = () => <div>I'm a child</div>;
const wrapper = shallow(<LeftMenuSection><Child /></LeftMenuSection>);
expect(wrapper.find(Child).exists()).toBe(true);
});
});

View File

@ -0,0 +1,29 @@
/**
*
* LeftMenuSectionTitle
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import styles from './styles.scss';
function LeftMenuSectionTitle({ id }) {
return (
<p className={styles.leftMenuSectionTitle}>
<FormattedMessage id={id} />
</p>
);
}
LeftMenuSectionTitle.defaultProps = {
id: 'app.utils.defaultMessage',
};
LeftMenuSectionTitle.propTypes = {
id: PropTypes.string,
};
export default LeftMenuSectionTitle;

View File

@ -0,0 +1,12 @@
.leftMenuSectionTitle {
-webkit-font-smoothing: antialiased;
margin: 0;
padding-left: 1.5rem;
line-height: 1.3rem;
color: #919BAE;
letter-spacing: 0.1rem;
font-family: Lato;
font-size: 1.1rem;
font-weight: bold;
text-transform: uppercase;
}

View File

@ -0,0 +1,9 @@
import React from 'react';
import { shallow } from 'enzyme';
import LeftMenuSectionTitle from '../index';
describe('<LeftMenuSectionTitle />', () => {
it('should not crash', () => {
shallow(<LeftMenuSectionTitle />);
});
});

View File

@ -0,0 +1,24 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import cn from 'classnames';
import pluginId from '../../pluginId';
import styles from './styles.scss';
const CustomLink = ({ onClick }) => (
<li style={{ color: '#2D3138' }}>
<div className={cn(styles.linkContainer, styles.iconPlus)} onClick={onClick}>
<div>
<i className="fa fa-plus" />
</div>
<span><FormattedMessage id={`${pluginId}.button.contentType.add`} /></span>
</div>
</li>
);
CustomLink.propTypes = {
onClick: PropTypes.func.isRequired,
};
export default CustomLink;

View File

@ -0,0 +1,17 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
const DocumentationSection = () => (
<ul style={{ marginTop: '20px' }}>
<li style={{ marginLeft: '4.5rem'}}>
<FormattedMessage id="content-type-builder.menu.section.documentation.guide" />&nbsp;
<FormattedMessage id="content-type-builder.menu.section.documentation.guideLink">
{(message) => (
<a href="http://strapi.io/documentation/3.x.x/guides/models.html" target="_blank">{message}</a>
)}
</FormattedMessage>
</li>
</ul>
);
export default DocumentationSection;

View File

@ -11,22 +11,73 @@ import { createStructuredSelector } from 'reselect';
import { bindActionCreators, compose } from 'redux';
import pluginId from '../../pluginId';
import PluginLeftMenu from '../../components/PluginLeftMenu';
import LeftMenu from '../../components/LeftMenu';
import LeftMenuSection from '../../components/LeftMenuSection';
import LeftMenuSectionTitle from '../../components/LeftMenuSectionTitle';
import LeftMenuLink from '../../components/LeftMenuLink';
import CustomLink from './CustomLink';
import makeSelectModelPage from './selectors';
import reducer from './reducer';
import saga from './saga';
import styles from './styles.scss';
import DocumentationSection from './DocumentationSection';
export class ModelPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
getSectionTitle = () => {
const base = `${pluginId}.menu.section.contentTypeBuilder.name.`;
return this.getModelNumber() > 1 ? `${base}plural` : `${base}singular`;
}
getModelNumber = () => {
const { models } = this.props;
return models.length;
}
handleClick = () => {}
renderLinks = () => {
const { models } = this.props;
const links = models.map(model => {
const { name, source } = model;
const base = `/plugins/${pluginId}/models/${name}`;
const to = source ? `${base}&source=${source}` : base;
return (
<LeftMenuLink
key={name}
icon="fa fa-caret-square-o-right"
name={name}
source={source}
to={to}
/>
);
});
return links;
}
render() {
return (
<div className={styles.modelpage}>
<div className="container-fluid">
<div className="row">
<PluginLeftMenu
sections={[]}
/>
<LeftMenu>
<LeftMenuSection>
<LeftMenuSectionTitle id={this.getSectionTitle()} />
<ul>
{this.renderLinks()}
<CustomLink onClick={this.handleClick} />
</ul>
</LeftMenuSection>
<LeftMenuSection>
<LeftMenuSectionTitle id={`${pluginId}.menu.section.documentation.name`} />
<DocumentationSection />
</LeftMenuSection>
</LeftMenu>
</div>
</div>
</div>
@ -34,7 +85,9 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
}
}
ModelPage.propTypes = {};
ModelPage.propTypes = {
models: PropTypes.array,
};
const mapStateToProps = createStructuredSelector({
modelpage: makeSelectModelPage(),

View File

@ -30,3 +30,21 @@
}
}
}
.linkContainer {
display: flex;
margin-left: 2rem;
margin-right: .5rem;
padding-top: 1rem;
padding-left: 1rem;
min-height: 3.4rem;
color: #1C8FE5 !important;
text-decoration: none !important;
line-height: 1.6rem;
cursor: pointer;
> div {
width: 1.3rem;
margin-right: 1rem;
}
}