mirror of
https://github.com/strapi/strapi.git
synced 2025-10-29 17:04:13 +00:00
Design ImgPReview slider and remoive dynamic
This commit is contained in:
parent
aaff3e8f87
commit
010c3f8072
@ -11,6 +11,8 @@
|
|||||||
"app.components.HomePage.button": "Create your first content type",
|
"app.components.HomePage.button": "Create your first content type",
|
||||||
"app.components.HomePage.feedback": "Feel free to ask questions or give us feedback by using one of the support channels below.",
|
"app.components.HomePage.feedback": "Feel free to ask questions or give us feedback by using one of the support channels below.",
|
||||||
|
|
||||||
|
"app.components.InputFile.newFile": "ADD NEW FILE",
|
||||||
|
|
||||||
"app.components.InstallPluginPage.helmet": "Install plugins",
|
"app.components.InstallPluginPage.helmet": "Install plugins",
|
||||||
"app.components.InstallPluginPage.title": "Install new plugins",
|
"app.components.InstallPluginPage.title": "Install new plugins",
|
||||||
"app.components.InstallPluginPage.description": "Extend your app with no efforts",
|
"app.components.InstallPluginPage.description": "Extend your app with no efforts",
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
"app.components.HomePage.button": "Créez votre premier type de contenu",
|
"app.components.HomePage.button": "Créez votre premier type de contenu",
|
||||||
"app.components.HomePage.feedback": "N'hésitez pas à utiliser un des channels ci-dessous pour poser vos questions ou nous donner vos retours.",
|
"app.components.HomePage.feedback": "N'hésitez pas à utiliser un des channels ci-dessous pour poser vos questions ou nous donner vos retours.",
|
||||||
|
|
||||||
|
"app.components.InputFile.newFile": "AJOUTER UN NOUVEAU FICHIER",
|
||||||
|
|
||||||
"app.components.InstallPluginPage.helmet": "Installez des plugins",
|
"app.components.InstallPluginPage.helmet": "Installez des plugins",
|
||||||
"app.components.InstallPluginPage.title": "Installez des nouveaux plugins",
|
"app.components.InstallPluginPage.title": "Installez des nouveaux plugins",
|
||||||
"app.components.InstallPluginPage.description": "Améliorez votre app sans efforts",
|
"app.components.InstallPluginPage.description": "Améliorez votre app sans efforts",
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { get, isEmpty, isObject } from 'lodash';
|
import { cloneDeep, get, isEmpty, isObject, size } from 'lodash';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
|
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
@ -16,8 +16,10 @@ class ImgPreview extends React.Component {
|
|||||||
state = { imgURL: '', position: 0 };
|
state = { imgURL: '', position: 0 };
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
// We don't need the generateImgURL function here since the compo will
|
||||||
|
// always have an init value here
|
||||||
this.setState({
|
this.setState({
|
||||||
imgURL: get(this.props.files, ['0', 'url']),
|
imgURL: get(this.props.files, ['0', 'url'], ''),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,18 +48,18 @@ class ImgPreview extends React.Component {
|
|||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick = (operator) => {
|
handleClick = (type) => {
|
||||||
const { position } = this.state;
|
const { position } = this.state;
|
||||||
const { files } = this.props;
|
const { files } = this.props;
|
||||||
let file;
|
let file;
|
||||||
let nextPosition;
|
let nextPosition;
|
||||||
|
|
||||||
switch (operator) {
|
switch (type) {
|
||||||
case '+':
|
case 'right':
|
||||||
file = files[position + 1] || files[0];
|
file = files[position + 1] || files[0];
|
||||||
nextPosition = files[position + 1] ? position + 1 : 0;
|
nextPosition = files[position + 1] ? position + 1 : 0;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case 'left':
|
||||||
file = files[position - 1] || files[files.length - 1];
|
file = files[position - 1] || files[files.length - 1];
|
||||||
nextPosition = files[position - 1] ? position - 1 : files.length - 1;
|
nextPosition = files[position - 1] ? position - 1 : files.length - 1;
|
||||||
break;
|
break;
|
||||||
@ -74,16 +76,67 @@ class ImgPreview extends React.Component {
|
|||||||
this.setState({ position: nextPosition });
|
this.setState({ position: nextPosition });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeFile = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const value = cloneDeep(this.props.files);
|
||||||
|
value.splice(this.state.position, 1);
|
||||||
|
|
||||||
|
const nextPosition = this.state.position - 1 === -1 ? 0 : this.state.position - 1;
|
||||||
|
const nextFile = value[nextPosition];
|
||||||
|
|
||||||
|
if (!isEmpty(nextFile)) {
|
||||||
|
if (!nextFile.url) {
|
||||||
|
this.generateImgURL(nextFile);
|
||||||
|
} else {
|
||||||
|
this.setState({ imgURL: nextFile.url });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setState({ imgURL: '' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = {
|
||||||
|
name: this.props.name,
|
||||||
|
type: 'file',
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setState({ position: nextPosition });
|
||||||
|
|
||||||
|
this.props.onChange({ target });
|
||||||
|
}
|
||||||
|
|
||||||
|
renderArrow = (type = 'left') => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
styles.arrowContainer,
|
||||||
|
type === 'left' && styles.arrowLeft,
|
||||||
|
type !== 'left' && styles.arrowRight,
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.handleClick(type);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
renderIconRemove = () => (
|
||||||
|
<div className={styles.iconContainer} onClick={this.removeFile}>
|
||||||
|
<i className="fa fa-times" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { files, multiple } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.imgPreviewContainer}>
|
||||||
|
{!isEmpty(files) && this.renderIconRemove()}
|
||||||
<img src={this.state.imgURL} />
|
<img src={this.state.imgURL} />
|
||||||
<button className="btn btn-primary" onClick={() => this.handleClick('+')}>
|
{ multiple && size(files) > 1 && this.renderArrow('right')}
|
||||||
+
|
{ multiple && size(files) > 1 && this.renderArrow('left')}
|
||||||
</button>
|
|
||||||
<button className="btn btn-primary" onClick={() => this.handleClick('-')}>
|
|
||||||
-
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -92,11 +145,17 @@ class ImgPreview extends React.Component {
|
|||||||
ImgPreview.defaultProps = {
|
ImgPreview.defaultProps = {
|
||||||
files: [{}],
|
files: [{}],
|
||||||
isUploading: false,
|
isUploading: false,
|
||||||
|
multiple: false,
|
||||||
|
name: '',
|
||||||
|
onChange: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
ImgPreview.propTypes = {
|
ImgPreview.propTypes = {
|
||||||
files: PropTypes.array,
|
files: PropTypes.array,
|
||||||
isUploading: PropTypes.bool,
|
isUploading: PropTypes.bool,
|
||||||
|
multiple: PropTypes.bool,
|
||||||
|
name: PropTypes.string,
|
||||||
|
onChange: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImgPreview;
|
export default ImgPreview;
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
.imgPreviewContainer {
|
||||||
|
display: table-cell;
|
||||||
|
height: 144px;
|
||||||
|
width: 358px;
|
||||||
|
position: relative;
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
// background-color: red;
|
||||||
|
background-color: #F3F4F4;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
> img {
|
||||||
|
max-width: 358px;
|
||||||
|
max-height: 144px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconContainer {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 3px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 11px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowContainer {
|
||||||
|
height: 32px;
|
||||||
|
width: 28px;
|
||||||
|
background: rgba(0,0,0,0.20);
|
||||||
|
border-radius: 2px 0 0 2px;
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowRight {
|
||||||
|
position: absolute;
|
||||||
|
top: 56px;
|
||||||
|
right: 0;
|
||||||
|
&:before {
|
||||||
|
content: '\f105';
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowLeft {
|
||||||
|
position: absolute;
|
||||||
|
top: 56px;
|
||||||
|
left: 0;
|
||||||
|
&:before {
|
||||||
|
content: '\f104';
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { cloneDeep, isArray, isObject, isEmpty, last } from 'lodash';
|
import { cloneDeep, isArray, isObject, isEmpty, last } from 'lodash';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
|
|
||||||
@ -44,16 +45,28 @@ class InputFile extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ImgPreview
|
<label
|
||||||
files={value}
|
>
|
||||||
isUploading={this.state.isUploading}
|
<ImgPreview
|
||||||
/>
|
files={value}
|
||||||
<input
|
isUploading={this.state.isUploading}
|
||||||
multiple={multiple}
|
multiple={multiple}
|
||||||
name={name}
|
name={name}
|
||||||
onChange={this.handleChange}
|
onChange={onChange}
|
||||||
type="file"
|
/>
|
||||||
/>
|
<input
|
||||||
|
className={styles.inputFile}
|
||||||
|
multiple={multiple}
|
||||||
|
name={name}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
type="file"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.buttonContainer}>
|
||||||
|
<i className="fa fa-plus" />
|
||||||
|
<FormattedMessage id="app.components.InputFile.newFile" />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
.inputFile {
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: 34px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #FAFAFB;
|
||||||
|
border: 1px solid #E3E9F3;
|
||||||
|
border-top: 0;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
|
||||||
|
color: #333740;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
line-height: 34px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
> i {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -33,12 +33,14 @@ export class HomePage extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.homePage}>
|
<div className={styles.homePage} style={{ paddingTop: '100px', marginLeft: '100px'}}>
|
||||||
<InputFile
|
<form>
|
||||||
name="test"
|
<InputFile
|
||||||
value={this.state.value}
|
name="test"
|
||||||
onChange={this.onChange}
|
value={this.state.value}
|
||||||
/>
|
onChange={this.onChange}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user