mirror of
https://github.com/strapi/strapi.git
synced 2025-08-16 04:34:40 +00:00
Display menu in modelPage
This commit is contained in:
parent
e2de03a862
commit
b4b025cd17
File diff suppressed because one or more lines are too long
@ -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;
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
@ -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;
|
||||||
|
}
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
@ -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;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import LeftMenuSectionTitle from '../index';
|
||||||
|
|
||||||
|
describe('<LeftMenuSectionTitle />', () => {
|
||||||
|
it('should not crash', () => {
|
||||||
|
shallow(<LeftMenuSectionTitle />);
|
||||||
|
});
|
||||||
|
});
|
@ -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;
|
@ -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" />
|
||||||
|
<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;
|
@ -11,22 +11,73 @@ import { createStructuredSelector } from 'reselect';
|
|||||||
import { bindActionCreators, compose } from 'redux';
|
import { bindActionCreators, compose } from 'redux';
|
||||||
import pluginId from '../../pluginId';
|
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 makeSelectModelPage from './selectors';
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
import saga from './saga';
|
import saga from './saga';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
import DocumentationSection from './DocumentationSection';
|
||||||
|
|
||||||
export class ModelPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.modelpage}>
|
<div className={styles.modelpage}>
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<PluginLeftMenu
|
<LeftMenu>
|
||||||
sections={[]}
|
<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>
|
</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({
|
const mapStateToProps = createStructuredSelector({
|
||||||
modelpage: makeSelectModelPage(),
|
modelpage: makeSelectModelPage(),
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user