Support drag-and-drop file publishing #4170
62
ui/component/common/file-list.jsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import Icon from 'component/common/icon';
|
||||
import classnames from 'classnames';
|
||||
import { useRadioState, Radio, RadioGroup } from 'reakit/Radio';
|
||||
|
||||
type Props = {
|
||||
files: Array<WebFile>,
|
||||
onChange: (WebFile | void) => void,
|
||||
};
|
||||
|
||||
function FileList(props: Props) {
|
||||
const { files, onChange } = props;
|
||||
const radio = useRadioState();
|
||||
|
||||
const getFile = (value?: string) => {
|
||||
if (files && files.length) {
|
||||
return files.find((file: WebFile) => file.name === value);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (radio.stops.length) {
|
||||
if (!radio.currentId) {
|
||||
radio.first();
|
||||
} else {
|
||||
const first = radio.stops[0].ref.current;
|
||||
// First auto-selection
|
||||
if (first && first.id === radio.currentId && !radio.state) {
|
||||
radio.setState(first.value);
|
||||
}
|
||||
|
||||
if (onChange && radio.state && radio.state !== '') {
|
||||
const file = getFile(radio.state);
|
||||
onChange(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [radio, onChange]);
|
||||
|
||||
return (
|
||||
<div className={'file-list'}>
|
||||
<RadioGroup {...radio} aria-label="files">
|
||||
{files.map((entry, index) => {
|
||||
const item = radio.stops[index];
|
||||
const selected = item && item.id === radio.currentId;
|
||||
|
||||
return (
|
||||
<label key={entry.name} className={classnames(selected && 'selected')}>
|
||||
<Radio {...radio} value={entry.name} />
|
||||
<Icon size={18} selected={selected} icon={selected ? ICONS.COMPLETED : ICONS.CIRCLE} />
|
||||
<span>{entry.name}</span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</RadioGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FileList;
|
|
@ -1,32 +1,22 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectBalance,
|
||||
selectIsStillEditing,
|
||||
makeSelectPublishFormValue,
|
||||
doUpdatePublishForm,
|
||||
doToast,
|
||||
doClearPublish,
|
||||
} from 'lbry-redux';
|
||||
import { selectFfmpegStatus } from 'redux/selectors/settings';
|
||||
|
||||
import { doToast, doClearPublish, doUpdatePublishForm, makeSelectPublishFormValue } from 'lbry-redux';
|
||||
|
||||
import { selectModal } from 'redux/selectors/app';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
|
||||
import FileDrop from './view';
|
||||
|
||||
const select = state => ({
|
||||
name: makeSelectPublishFormValue('name')(state),
|
||||
modal: selectModal(state),
|
||||
filePath: makeSelectPublishFormValue('filePath')(state),
|
||||
optimize: makeSelectPublishFormValue('optimize')(state),
|
||||
isStillEditing: selectIsStillEditing(state),
|
||||
balance: selectBalance(state),
|
||||
publishing: makeSelectPublishFormValue('publishing')(state),
|
||||
ffmpegStatus: selectFfmpegStatus(state),
|
||||
size: makeSelectPublishFormValue('fileSize')(state),
|
||||
duration: makeSelectPublishFormValue('fileDur')(state),
|
||||
isVid: makeSelectPublishFormValue('fileVid')(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
showToast: message => dispatch(doToast({ message, isError: true })),
|
||||
clearPublish: () => dispatch(doClearPublish()),
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
showToast: message => dispatch(doToast({ message, isError: true })),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(FileDrop);
|
||||
|
|
|
@ -2,17 +2,20 @@
|
|||
![]() ok, done. ok, done.
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
import React from 'react';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import Icon from 'component/common/icon';
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
import classnames from 'classnames';
|
||||
import useDragDrop from 'effects/use-drag-drop';
|
||||
import { getTree } from 'util/web-file-system';
|
||||
import { withRouter } from 'react-router';
|
||||
import { useRadioState, Radio, RadioGroup } from 'reakit/Radio';
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
import Icon from 'component/common/icon';
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
import FileList from 'component/common/file-list';
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
type Props = {
|
||||
modal: { id: string, modalProps: {} },
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
filePath: string | WebFile,
|
||||
clearPublish: () => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
openModal: (id: string, { files: Array<WebFile> }) => void,
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// React router
|
||||
history: {
|
||||
entities: {}[],
|
||||
|
@ -25,51 +28,14 @@ type Props = {
|
|||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
},
|
||||
};
|
||||
|
||||
type FileListProps = {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
files: Array<WebFile>,
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
onSelected: string => void,
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
};
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const HIDE_TIME_OUT = 600;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const NAVIGATE_TIME_OUT = 300;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const PUBLISH_URL = `/$/${PAGES.PUBLISH}`;
|
||||
|
||||
function FileList(props: FileListProps) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const { files, onSelected } = props;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const radio = useRadioState();
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
React.useEffect(() => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (!radio.currentId) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
radio.first();
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (radio.state && radio.state !== '') {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
onSelected(radio.state);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, [radio, onSelected]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
return (
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<RadioGroup {...radio} aria-label="fruits">
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
{files.map((entry, index) => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const item = radio.stops[index];
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const selected = item && item.id === radio.currentId;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
return (
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<label key={entry.name} className={classnames(selected && 'selected')}>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<Radio {...radio} value={entry.name} />
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<Icon size={18} selected={selected} icon={selected ? ICONS.COMPLETED : ICONS.CIRCLE} />
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<span>{entry.name}</span>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
</label>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
})}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
</RadioGroup>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
function FileDrop(props: Props) {
|
||||
const { history, filePath, updatePublishForm } = props;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const { modal, history, openModal, updatePublishForm } = props;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const { drag, dropData } = useDragDrop();
|
||||
const [show, setShow] = React.useState(false);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const [files, setFiles] = React.useState([]);
|
||||
const [selectedFile, setSelectedFile] = React.useState('');
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const [error, setError] = React.useState(false);
|
||||
|
||||
const navigateToPublish = React.useCallback(() => {
|
||||
|
@ -80,18 +46,29 @@ function FileDrop(props: Props) {
|
|||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
}, [history]);
|
||||
|
||||
const handleFileSelected = name => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (files && files.length) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const selected = files.find(file => file.name === name);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (selected && selected.name !== (selectedFile && selectedFile.name)) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setSelectedFile(selected);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Delay hide and navigation for a smooth transition
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const hideDropArea = () => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setTimeout(() => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setFiles([]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setTimeout(() => navigateToPublish(), NAVIGATE_TIME_OUT);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, HIDE_TIME_OUT);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
![]() This feels really smooth 👍 This feels really smooth 👍
|
||||
};
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const handleFileSelected = selectedFile => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
updatePublishForm({ filePath: selectedFile });
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
hideDropArea();
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
};
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Firt file will be selected by default:
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const handleFileChange = (file?: WebFile) => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (files && files.length && file) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
handleFileSelected(file);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
// Handle drop...
|
||||
if (dropData) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (dropData && !files.length && (!modal || modal.id !== MODALS.FILE_SELECTION)) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
getTree(dropData)
|
||||
.then(entries => {
|
||||
if (entries && entries.length) {
|
||||
|
@ -99,59 +76,30 @@ function FileDrop(props: Props) {
|
|||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Invalid entry / entries
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setError(error || true);
|
||||
});
|
||||
}
|
||||
}, [dropData]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, [dropData, files, modal]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
React.useEffect(() => {
|
||||
// Files are drag over or already dropped
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (drag || files.length) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setShow(true);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// No drag over or files dropped
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
} else if (!drag && !files.length) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setShow(false);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Filew dropped on drop area
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Files or directory dropped:
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (!drag && files.length) {
|
||||
if (files.length === 1) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Handle single file publish
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setSelectedFile(files[0]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
updatePublishForm({ filePath: files[0] });
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Handle files
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, [drag, files, error, updatePublishForm, setSelectedFile]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Wait for publish state update:
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
React.useEffect(() => {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
/*
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Publish form has a file
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (selectedFile && filePath) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Update completed
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (selectedFile.path === filePath.path) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Done! close the drop area:
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
// Handle multiple files selection
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
if (files.length > 1) {
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
openModal(MODALS.FILE_SELECTION, { files: files });
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
setFiles([]);
|
||||
// Go to publish area
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
navigateToPublish();
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}
|
||||
}
|
||||
*/
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, [filePath, selectedFile, navigateToPublish, setFiles]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
}, [drag, files, error]);
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
const show = files.length === 1 || (drag && (!modal || modal.id !== MODALS.FILE_SELECTION));
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
|
||||
const multipleFiles = files.length > 1;
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
return (
|
||||
<div className={classnames('file-drop', show && 'file-drop--show')}>
|
||||
<div className={classnames('card', 'file-drop__area')}>
|
||||
<Icon size={64} icon={multipleFiles ? ICONS.ALERT : ICONS.PUBLISH} className={'main-icon'} />
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<p>{multipleFiles ? `Only one file is allowed choose wisely` : `Drop here to publish!`} </p>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
{files && files.length > 0 && (
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<div className="file-drop__list">
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<FileList files={files} onSelected={handleFileSelected} />
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
</div>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
)}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<Icon size={64} icon={ICONS.PUBLISH} className={'main-icon'} />
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
<p>{`Drop here to publish!`} </p>
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
{files && files.length === 1 && <FileList files={files} onChange={handleFileChange} />}
|
||||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|||
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
![]() Please wrap this in Please wrap this in `__()`
![]() ok, done. ok, done.
|
|
@ -3,6 +3,7 @@ export const CONFIRM_EXTERNAL_RESOURCE = 'confirm_external_resource';
|
|||
export const COMMENT_ACKNOWEDGEMENT = 'comment_acknowlegement';
|
||||
export const INCOMPATIBLE_DAEMON = 'incompatible_daemon';
|
||||
export const FILE_TIMEOUT = 'file_timeout';
|
||||
export const FILE_SELECTION = 'file_selection';
|
||||
export const DOWNLOADING = 'downloading';
|
||||
export const AUTO_GENERATE_THUMBNAIL = 'auto_generate_thumbnail';
|
||||
export const AUTO_UPDATE_DOWNLOADED = 'auto_update_downloaded';
|
||||
|
|
12
ui/modal/modalFileSelection/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import { doUpdatePublishForm } from 'lbry-redux';
|
||||
|
||||
import ModaFileSelection from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
hideModal: props => dispatch(doHideModal(props)),
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(ModaFileSelection);
|
77
ui/modal/modalFileSelection/view.jsx
Normal file
|
@ -0,0 +1,77 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import { withRouter } from 'react-router';
|
||||
import Card from 'component/common/card';
|
||||
import Button from 'component/button';
|
||||
import FileList from 'component/common/file-list';
|
||||
|
||||
type Props = {
|
||||
files: Array<WebFile>,
|
||||
hideModal: () => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
history: {
|
||||
location: { pathname: string },
|
||||
push: string => void,
|
||||
},
|
||||
};
|
||||
|
||||
const PUBLISH_URL = `/$/${PAGES.PUBLISH}`;
|
||||
|
||||
const ModalFileSelection = (props: Props) => {
|
||||
const { history, files, hideModal, updatePublishForm } = props;
|
||||
const [selectedFile, setSelectedFile] = React.useState(null);
|
||||
|
||||
const navigateToPublish = React.useCallback(() => {
|
||||
// Navigate only if location is not publish area:
|
||||
// - Prevent spam in history
|
||||
if (history.location.pathname !== PUBLISH_URL) {
|
||||
history.push(PUBLISH_URL);
|
||||
}
|
||||
}, [history]);
|
||||
|
||||
function handleCloseModal() {
|
||||
hideModal();
|
||||
setSelectedFile(null);
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
updatePublishForm({ filePath: selectedFile });
|
||||
handleCloseModal();
|
||||
navigateToPublish();
|
||||
}
|
||||
|
||||
const handleFileChange = (file?: WebFile) => {
|
||||
setSelectedFile(file);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen type="card" onAborted={handleCloseModal} onConfirmed={handleCloseModal}>
|
||||
<Card
|
||||
icon={ICONS.PUBLISH}
|
||||
title={__('Choose a file')}
|
||||
subtitle={__('Only one file is allowed, choose wisely:')}
|
||||
actions={
|
||||
<div>
|
||||
<div>
|
||||
<FileList files={files} onChange={handleFileChange} />
|
||||
</div>
|
||||
<div className="section__actions">
|
||||
<Button
|
||||
disabled={!selectedFile || !files || !files.length}
|
||||
button="primary"
|
||||
label={__('Accept')}
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
<Button button="link" label={__('Cancel')} onClick={handleCloseModal} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(ModalFileSelection);
|
|
@ -39,6 +39,7 @@ import ModalRepost from 'modal/modalRepost';
|
|||
import ModalSignOut from 'modal/modalSignOut';
|
||||
import ModalLiquidateSupports from 'modal/modalSupportsLiquidate';
|
||||
import ModalConfirmAge from 'modal/modalConfirmAge';
|
||||
import ModalFileSelection from 'modal/modalFileSelection';
|
||||
|
||||
type Props = {
|
||||
modal: { id: string, modalProps: {} },
|
||||
|
@ -140,6 +141,8 @@ function ModalRouter(props: Props) {
|
|||
return <ModalLiquidateSupports {...modalProps} />;
|
||||
case MODALS.CONFIRM_AGE:
|
||||
return <ModalConfirmAge {...modalProps} />;
|
||||
case MODALS.FILE_SELECTION:
|
||||
return <ModalFileSelection {...modalProps} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
@import 'component/expandable';
|
||||
@import 'component/expanding-details';
|
||||
@import 'component/file-drop';
|
||||
@import 'component/file-list';
|
||||
@import 'component/file-properties';
|
||||
@import 'component/file-render';
|
||||
@import 'component/footer';
|
||||
|
|
|
@ -23,52 +23,15 @@
|
|||
|
||||
.file-drop__area {
|
||||
display: flex;
|
||||
min-width: 400px;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: var(--spacing-large);
|
||||
min-width: 400px;
|
||||
|
||||
.file-drop__list {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
fieldset {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background: var(--color-menu-background);
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-miniscule) var(--spacing-small);
|
||||
|
||||
&.selected {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 0 0 3px var(--color-focus);
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: var(--spacing-small);
|
||||
opacity: 0.64;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
margin: var(--spacing-small);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: var(--spacing-large);
|
||||
}
|
||||
|
|
37
ui/scss/component/_file-list.scss
Normal file
|
@ -0,0 +1,37 @@
|
|||
.file-list {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
fieldset {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background: var(--color-menu-background);
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-miniscule) var(--spacing-small);
|
||||
|
||||
&.selected {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 0 0 3px var(--color-focus);
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: var(--spacing-small);
|
||||
opacity: 0.64;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
Please wrap this in
__()