mirror of
https://github.com/strapi/strapi.git
synced 2025-08-14 19:56:41 +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 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(),
|
||||
|
@ -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