add in-app text and markdown publishing
This commit is contained in:
parent
80d8eeb4cf
commit
a5d1746151
9 changed files with 354 additions and 40 deletions
|
@ -3,7 +3,6 @@ import { doUpdatePublishForm, makeSelectPublishFormValue } from 'lbry-redux';
|
|||
import PublishPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
title: makeSelectPublishFormValue('title')(state),
|
||||
description: makeSelectPublishFormValue('description')(state),
|
||||
});
|
||||
|
||||
|
@ -11,7 +10,4 @@ const perform = dispatch => ({
|
|||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(PublishPage);
|
||||
export default connect(select, perform)(PublishPage);
|
|
@ -7,14 +7,13 @@ import usePersistedState from 'effects/use-persisted-state';
|
|||
import Card from 'component/common/card';
|
||||
|
||||
type Props = {
|
||||
title: ?string,
|
||||
description: ?string,
|
||||
disabled: boolean,
|
||||
updatePublishForm: ({}) => void,
|
||||
};
|
||||
|
||||
function PublishText(props: Props) {
|
||||
const { title, description, updatePublishForm, disabled } = props;
|
||||
const { description, updatePublishForm, disabled } = props;
|
||||
const [advancedEditor, setAdvancedEditor] = usePersistedState('publish-form-description-mode', false);
|
||||
function toggleMarkdown() {
|
||||
setAdvancedEditor(!advancedEditor);
|
||||
|
@ -24,16 +23,6 @@ function PublishText(props: Props) {
|
|||
<Card
|
||||
actions={
|
||||
<React.Fragment>
|
||||
<FormField
|
||||
type="text"
|
||||
name="content_title"
|
||||
label={__('Title')}
|
||||
placeholder={__('Descriptive titles work best')}
|
||||
disabled={disabled}
|
||||
value={title}
|
||||
onChange={e => updatePublishForm({ title: e.target.value })}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
type={!SIMPLE_SITE && advancedEditor ? 'markdown' : 'textarea'}
|
||||
name="content_description"
|
|
@ -12,6 +12,7 @@ import PublishPage from './view';
|
|||
|
||||
const select = state => ({
|
||||
name: makeSelectPublishFormValue('name')(state),
|
||||
title: makeSelectPublishFormValue('title')(state),
|
||||
filePath: makeSelectPublishFormValue('filePath')(state),
|
||||
optimize: makeSelectPublishFormValue('optimize')(state),
|
||||
isStillEditing: selectIsStillEditing(state),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import * as ICONS from 'constants/icons';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { regexInvalidURI } from 'lbry-redux';
|
||||
import StoryEditor from 'component/storyEditor';
|
||||
import FileSelector from 'component/common/file-selector';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
|
@ -9,9 +10,13 @@ import { FormField } from 'component/common/form';
|
|||
import Spinner from 'component/spinner';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import usePersistedState from 'effects/use-persisted-state';
|
||||
import * as PUBLISH_MODES from 'constants/publish_types';
|
||||
|
||||
type Props = {
|
||||
uri: ?string,
|
||||
mode: ?string,
|
||||
name: ?string,
|
||||
title: ?string,
|
||||
filePath: string | WebFile,
|
||||
isStillEditing: boolean,
|
||||
balance: number,
|
||||
|
@ -26,11 +31,16 @@ type Props = {
|
|||
size: number,
|
||||
duration: number,
|
||||
isVid: boolean,
|
||||
setPublishMode: string => void,
|
||||
setPrevFileText: string => void,
|
||||
};
|
||||
|
||||
function PublishFile(props: Props) {
|
||||
const {
|
||||
uri,
|
||||
mode,
|
||||
name,
|
||||
title,
|
||||
balance,
|
||||
filePath,
|
||||
isStillEditing,
|
||||
|
@ -44,11 +54,14 @@ function PublishFile(props: Props) {
|
|||
size,
|
||||
duration,
|
||||
isVid,
|
||||
setPublishMode,
|
||||
setPrevFileText,
|
||||
} = props;
|
||||
|
||||
const ffmpegAvail = ffmpegStatus.available;
|
||||
const [oversized, setOversized] = useState(false);
|
||||
const [currentFile, setCurrentFile] = useState(null);
|
||||
const [currentFileType, setCurrentFileType] = useState(null);
|
||||
const [optimizeAvail, setOptimizeAvail] = useState(false);
|
||||
const [userOptimize, setUserOptimize] = usePersistedState('publish-file-user-optimize', false);
|
||||
|
||||
|
@ -58,11 +71,20 @@ function PublishFile(props: Props) {
|
|||
const PROCESSING_MB_PER_SECOND = 0.5;
|
||||
const MINUTES_THRESHOLD = 30;
|
||||
const HOURS_THRESHOLD = MINUTES_THRESHOLD * 60;
|
||||
const MARKDOWN_FILE_EXTENSIONS = ['txt', 'md', 'markdown'];
|
||||
|
||||
const sizeInMB = Number(size) / 1000000;
|
||||
const secondsToProcess = sizeInMB / PROCESSING_MB_PER_SECOND;
|
||||
|
||||
// clear warnings
|
||||
// Reset filePath if publish mode changed
|
||||
useEffect(() => {
|
||||
if (mode === PUBLISH_MODES.STORY) {
|
||||
if (currentFileType !== 'text/markdown') {
|
||||
updatePublishForm({ filePath: '', name: '' });
|
||||
}
|
||||
}
|
||||
}, [currentFileType, mode, updatePublishForm]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!filePath || filePath === '') {
|
||||
setCurrentFile('');
|
||||
|
@ -82,7 +104,7 @@ function PublishFile(props: Props) {
|
|||
|
||||
setOptimizeAvail(isOptimizeAvail);
|
||||
updatePublishForm({ optimize: finalOptimizeState });
|
||||
}, [currentFile, filePath, isVid, ffmpegAvail, userOptimize]);
|
||||
}, [currentFile, filePath, isVid, ffmpegAvail, userOptimize, updatePublishForm]);
|
||||
|
||||
function updateFileInfo(duration, size, isvid) {
|
||||
updatePublishForm({ fileDur: duration, fileSize: size, fileVid: isvid });
|
||||
|
@ -201,6 +223,19 @@ function PublishFile(props: Props) {
|
|||
const contentType = file.type && file.type.split('/');
|
||||
const isVideo = contentType && contentType[0] === 'video';
|
||||
const isMp4 = contentType && contentType[1] === 'mp4';
|
||||
|
||||
let isMarkdownText = false;
|
||||
|
||||
if (contentType) {
|
||||
isMarkdownText = contentType[0] === 'text';
|
||||
setCurrentFileType(contentType);
|
||||
} else if (file.name) {
|
||||
// If user's machine is missign a valid content type registration
|
||||
// for markdown content: text/markdown, file extension will be used instead
|
||||
const extension = file.name.split('.').pop();
|
||||
isMarkdownText = MARKDOWN_FILE_EXTENSIONS.includes(extension);
|
||||
}
|
||||
|
||||
if (isVideo) {
|
||||
if (isMp4) {
|
||||
const video = document.createElement('video');
|
||||
|
@ -220,6 +255,22 @@ function PublishFile(props: Props) {
|
|||
updateFileInfo(0, file.size, isVideo);
|
||||
}
|
||||
|
||||
if (isMarkdownText) {
|
||||
// Create reader
|
||||
const reader = new FileReader();
|
||||
// Handler for file reader
|
||||
reader.addEventListener('load', event => {
|
||||
const text = event.target.result;
|
||||
updatePublishForm({ fileText: text });
|
||||
setPublishMode(PUBLISH_MODES.STORY);
|
||||
});
|
||||
// Read file contents
|
||||
reader.readAsText(file);
|
||||
setCurrentFileType('text/markdown');
|
||||
} else {
|
||||
setPublishMode(PUBLISH_MODES.FILE);
|
||||
}
|
||||
|
||||
// @if TARGET='web'
|
||||
// we only need to enforce file sizes on 'web'
|
||||
if (file.size && Number(file.size) > TV_PUBLISH_SIZE_LIMIT) {
|
||||
|
@ -247,43 +298,62 @@ function PublishFile(props: Props) {
|
|||
updatePublishForm(publishFormParams);
|
||||
}
|
||||
|
||||
let title;
|
||||
let cardTitle;
|
||||
if (publishing) {
|
||||
title = (
|
||||
cardTitle = (
|
||||
<span>
|
||||
{__('Uploading')}
|
||||
<Spinner type={'small'} />
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
title = isStillEditing ? __('Edit') : __('Upload');
|
||||
cardTitle = isStillEditing ? __('Edit') : __('Upload');
|
||||
}
|
||||
|
||||
const isPublishFile = mode === PUBLISH_MODES.FILE;
|
||||
const isPublishStory = mode === PUBLISH_MODES.STORY;
|
||||
|
||||
return (
|
||||
<Card
|
||||
icon={ICONS.PUBLISH}
|
||||
disabled={disabled || balance === 0}
|
||||
title={
|
||||
<React.Fragment>
|
||||
{title}{' '}
|
||||
{cardTitle}{' '}
|
||||
{inProgress && <Button button="close" label={__('Cancel')} icon={ICONS.REMOVE} onClick={clearPublish} />}
|
||||
</React.Fragment>
|
||||
}
|
||||
subtitle={isStillEditing && __('You are currently editing your upload.')}
|
||||
actions={
|
||||
<React.Fragment>
|
||||
<FileSelector disabled={disabled} currentPath={currentFile} onFileChosen={handleFileChange} />
|
||||
{getMessage()}
|
||||
{/* @if TARGET='app' */}
|
||||
<FormField
|
||||
type="checkbox"
|
||||
checked={userOptimize}
|
||||
disabled={!optimizeAvail}
|
||||
onChange={() => setUserOptimize(!userOptimize)}
|
||||
label={__('Optimize and transcode video')}
|
||||
name="optimize"
|
||||
type="text"
|
||||
name="content_title"
|
||||
label={__('Title')}
|
||||
placeholder={__('Descriptive titles work best')}
|
||||
disabled={disabled}
|
||||
value={title}
|
||||
onChange={e => updatePublishForm({ title: e.target.value })}
|
||||
/>
|
||||
{!ffmpegAvail && (
|
||||
{isPublishFile && (
|
||||
<FileSelector disabled={disabled} currentPath={currentFile} onFileChosen={handleFileChange} />
|
||||
)}
|
||||
{isPublishStory && (
|
||||
<StoryEditor label={__('Story content')} uri={uri} disabled={disabled} setPrevFileText={setPrevFileText} />
|
||||
)}
|
||||
{isPublishFile && getMessage()}
|
||||
{/* @if TARGET='app' */}
|
||||
{isPublishFile && (
|
||||
<FormField
|
||||
type="checkbox"
|
||||
checked={userOptimize}
|
||||
disabled={!optimizeAvail}
|
||||
onChange={() => setUserOptimize(!userOptimize)}
|
||||
label={__('Optimize and transcode video')}
|
||||
name="optimize"
|
||||
/>
|
||||
)}
|
||||
{isPublishFile && !ffmpegAvail && (
|
||||
<p className="help">
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
|
@ -294,7 +364,7 @@ function PublishFile(props: Props) {
|
|||
</I18nMessage>
|
||||
</p>
|
||||
)}
|
||||
{Boolean(size) && ffmpegAvail && optimize && isVid && (
|
||||
{isPublishFile && Boolean(size) && ffmpegAvail && optimize && isVid && (
|
||||
<p className="help">
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
On web, the Lbry publish method call is overridden in platform/web/api-setup, using a function in platform/web/publish.
|
||||
File upload is carried out in the background by that function.
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import { remote } from 'electron';
|
||||
import { SITE_NAME } from 'config';
|
||||
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
|
||||
import React, { useEffect } from 'react';
|
||||
|
@ -15,7 +17,7 @@ import Button from 'component/button';
|
|||
import SelectChannel from 'component/selectChannel';
|
||||
import classnames from 'classnames';
|
||||
import TagsSelect from 'component/tagsSelect';
|
||||
import PublishText from 'component/publishText';
|
||||
import PublishDescription from 'component/publishDescription';
|
||||
import PublishPrice from 'component/publishPrice';
|
||||
import PublishFile from 'component/publishFile';
|
||||
import PublishName from 'component/publishName';
|
||||
|
@ -24,12 +26,18 @@ import PublishFormErrors from 'component/publishFormErrors';
|
|||
import SelectThumbnail from 'component/selectThumbnail';
|
||||
import Card from 'component/common/card';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import * as PUBLISH_MODES from 'constants/publish_types';
|
||||
|
||||
const { dialog } = remote;
|
||||
const currentWindow = remote.getCurrentWindow();
|
||||
const MODES = Object.values(PUBLISH_MODES);
|
||||
|
||||
type Props = {
|
||||
disabled: boolean,
|
||||
tags: Array<Tag>,
|
||||
publish: (?string) => void,
|
||||
filePath: ?string,
|
||||
fileText: ?string,
|
||||
bid: ?number,
|
||||
bidError: ?string,
|
||||
editingURI: ?string,
|
||||
|
@ -73,6 +81,13 @@ type Props = {
|
|||
};
|
||||
|
||||
function PublishForm(props: Props) {
|
||||
const [mode, setMode] = React.useState(PUBLISH_MODES.FILE);
|
||||
const [autoSwitchMode, setAutoSwitchMode] = React.useState(true);
|
||||
|
||||
// Used to checl if the file has been modified by user
|
||||
const [fileEdited, setFileEdited] = React.useState(false);
|
||||
const [prevFileText, setPrevFileText] = React.useState('');
|
||||
|
||||
const {
|
||||
thumbnail,
|
||||
name,
|
||||
|
@ -87,6 +102,7 @@ function PublishForm(props: Props) {
|
|||
resetThumbnailStatus,
|
||||
updatePublishForm,
|
||||
filePath,
|
||||
fileText,
|
||||
publishing,
|
||||
clearPublish,
|
||||
isStillEditing,
|
||||
|
@ -97,6 +113,7 @@ function PublishForm(props: Props) {
|
|||
onChannelChange,
|
||||
ytSignupPending,
|
||||
} = props;
|
||||
|
||||
const TAGS_LIMIT = 5;
|
||||
const formDisabled = (!filePath && !editingURI) || publishing;
|
||||
const isInProgress = filePath || editingURI || name || title;
|
||||
|
@ -129,6 +146,15 @@ function PublishForm(props: Props) {
|
|||
}
|
||||
}, [thumbnail, resetThumbnailStatus]);
|
||||
|
||||
// Check for content changes on the text editor
|
||||
useEffect(() => {
|
||||
if (!fileEdited && fileText !== prevFileText && fileText !== '') {
|
||||
setFileEdited(true);
|
||||
} else if (fileEdited && fileText === prevFileText) {
|
||||
setFileEdited(false);
|
||||
}
|
||||
}, [fileText, prevFileText, fileEdited]);
|
||||
|
||||
// Every time the channel or name changes, resolve the uris to find winning bid amounts
|
||||
useEffect(() => {
|
||||
// If they are midway through a channel creation, treat it as anonymous until it completes
|
||||
|
@ -161,14 +187,127 @@ function PublishForm(props: Props) {
|
|||
updatePublishForm({ channel });
|
||||
}
|
||||
|
||||
function showSaveDialog() {
|
||||
return dialog.showSaveDialog(currentWindow, {
|
||||
filters: [{ name: 'Text', extensions: ['md', 'markdown', 'txt'] }],
|
||||
});
|
||||
}
|
||||
|
||||
function createWebFile() {
|
||||
if (fileText) {
|
||||
const fileName = name || title || 'story';
|
||||
return new File([fileText], `${fileName}.md`, { type: 'text/markdown' });
|
||||
}
|
||||
}
|
||||
|
||||
async function saveFileChanges() {
|
||||
let output = filePath;
|
||||
if (!output || output === '') {
|
||||
output = await showSaveDialog();
|
||||
}
|
||||
// User saved the file on a custom location
|
||||
if (typeof output === 'string') {
|
||||
// Save file changes
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(output, fileText, (error, data) => {
|
||||
// Handle error, cant save changes or create file
|
||||
error ? reject(error) : resolve(output);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function verifyStoryContent() {
|
||||
const isEmpty = !fileText || fileText.length === 0 || fileText === '';
|
||||
// TODO: Verify file size limit, and character size as well ?
|
||||
return !isEmpty;
|
||||
}
|
||||
|
||||
async function handlePublish() {
|
||||
// Publish story:
|
||||
// If here is no file selected yet on desktop, show file dialog and let the
|
||||
// user choose a file path. On web a new File is created
|
||||
if (mode === PUBLISH_MODES.STORY) {
|
||||
let outputFile = filePath;
|
||||
// If user modified content on the text editor:
|
||||
// Save changes and updat file path
|
||||
if (fileEdited) {
|
||||
// @if TARGET='app'
|
||||
outputFile = await saveFileChanges();
|
||||
// @endif
|
||||
|
||||
// @if TARGET='web'
|
||||
outputFile = createWebFile();
|
||||
// @endif
|
||||
|
||||
// New content stored locally and is not empty
|
||||
if (outputFile) {
|
||||
updatePublishForm({ filePath: outputFile });
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if story has a valid content and is not emoty
|
||||
// On web file size limit will be verified as well
|
||||
const verified = verifyStoryContent();
|
||||
|
||||
if (verified) {
|
||||
publish(outputFile);
|
||||
}
|
||||
}
|
||||
// Publish file
|
||||
if (mode === PUBLISH_MODES.FILE) {
|
||||
publish(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
function changePublishMode(name) {
|
||||
setMode(name);
|
||||
}
|
||||
|
||||
// Update mode on editing
|
||||
useEffect(() => {
|
||||
if (autoSwitchMode && editingURI && myClaimForUri) {
|
||||
const { media_type: mediaType } = myClaimForUri.value.source;
|
||||
// Change publish mode to "story" if editing content type is markdown
|
||||
if (mediaType === 'text/markdown' && mode !== PUBLISH_MODES.STORY) {
|
||||
setMode(PUBLISH_MODES.STORY);
|
||||
// Prevent forced mode
|
||||
setAutoSwitchMode(false);
|
||||
}
|
||||
}
|
||||
}, [autoSwitchMode, editingURI, myClaimForUri, mode, setMode, setAutoSwitchMode]);
|
||||
|
||||
// Editing claim uri
|
||||
const uri = myClaimForUri ? myClaimForUri.permanent_url : undefined;
|
||||
|
||||
return (
|
||||
<div className="card-stack">
|
||||
<PublishFile disabled={disabled || publishing} inProgress={isInProgress} />
|
||||
<div className="button-tab-group">
|
||||
{MODES.map((name, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
icon={name}
|
||||
label={name}
|
||||
button="alt"
|
||||
onClick={() => {
|
||||
changePublishMode(name);
|
||||
}}
|
||||
className={classnames('button-toggle', { 'button-toggle--active': mode === name })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<PublishFile
|
||||
uri={uri}
|
||||
mode={mode}
|
||||
disabled={disabled || publishing}
|
||||
inProgress={isInProgress}
|
||||
setPublishMode={setMode}
|
||||
setPrevFileText={setPrevFileText}
|
||||
/>
|
||||
{!publishing && (
|
||||
<div className={classnames({ 'card--disabled': formDisabled })}>
|
||||
<PublishText disabled={formDisabled} />
|
||||
{mode === PUBLISH_MODES.FILE && <PublishDescription disabled={formDisabled} />}
|
||||
<Card actions={<SelectThumbnail />} />
|
||||
|
||||
<TagsSelect
|
||||
suggestMature
|
||||
disableAutoFocus
|
||||
|
@ -217,7 +356,7 @@ function PublishForm(props: Props) {
|
|||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={() => publish(filePath)}
|
||||
onClick={handlePublish}
|
||||
label={submitLabel}
|
||||
disabled={
|
||||
formDisabled || !formValid || uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS || ytSignupPending
|
||||
|
|
21
ui/component/storyEditor/index.js
Normal file
21
ui/component/storyEditor/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectIsStillEditing,
|
||||
makeSelectPublishFormValue,
|
||||
doUpdatePublishForm,
|
||||
makeSelectFileInfoForUri,
|
||||
} from 'lbry-redux';
|
||||
import StoryEditor from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||
filePath: makeSelectPublishFormValue('filePath')(state),
|
||||
fileText: makeSelectPublishFormValue('fileText')(state),
|
||||
isStillEditing: selectIsStillEditing(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(StoryEditor);
|
91
ui/component/storyEditor/view.jsx
Normal file
91
ui/component/storyEditor/view.jsx
Normal file
|
@ -0,0 +1,91 @@
|
|||
// @flow
|
||||
import fs from 'fs';
|
||||
import React, { useEffect } from 'react';
|
||||
import { SIMPLE_SITE } from 'config';
|
||||
import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field';
|
||||
import { FormField } from 'component/common/form';
|
||||
import usePersistedState from 'effects/use-persisted-state';
|
||||
|
||||
type Props = {
|
||||
uri: ?string,
|
||||
label: ?string,
|
||||
disabled: ?boolean,
|
||||
fileInfo: FileListItem,
|
||||
filePath: string | WebFile,
|
||||
fileText: ?string,
|
||||
isStillEditing: boolean,
|
||||
setPrevFileText: string => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
};
|
||||
|
||||
function StoryEditor(props: Props) {
|
||||
const {
|
||||
uri,
|
||||
label,
|
||||
disabled,
|
||||
fileInfo,
|
||||
filePath,
|
||||
fileText,
|
||||
isStillEditing,
|
||||
setPrevFileText,
|
||||
updatePublishForm,
|
||||
} = props;
|
||||
|
||||
const [advancedEditor, setAdvancedEditor] = usePersistedState('publish-form-story-mode', false);
|
||||
|
||||
function toggleMarkdown() {
|
||||
setAdvancedEditor(!advancedEditor);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// @if TARGET='app'
|
||||
function readFile(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(path, 'utf8', (error, data) => {
|
||||
error ? reject(error) : resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function updateEditorText(path) {
|
||||
const text = await readFile(path);
|
||||
if (text) {
|
||||
// Store original content
|
||||
setPrevFileText(text);
|
||||
// Update text editor form
|
||||
updatePublishForm({ fileText: text });
|
||||
}
|
||||
}
|
||||
|
||||
const isEditingFile = isStillEditing && uri && fileInfo;
|
||||
|
||||
if (isEditingFile) {
|
||||
const { mime_type: mimeType, download_path: downloadPath } = fileInfo;
|
||||
|
||||
// Editing same file (previously published)
|
||||
// User can use a different file to replace the content
|
||||
if (!filePath && mimeType === 'text/markdown') {
|
||||
updateEditorText(downloadPath);
|
||||
}
|
||||
}
|
||||
|
||||
// @endif
|
||||
}, [uri, isStillEditing, filePath, fileInfo, setPrevFileText, updatePublishForm]);
|
||||
|
||||
return (
|
||||
<FormField
|
||||
type={!SIMPLE_SITE && advancedEditor ? 'markdown' : 'textarea'}
|
||||
name="content_story"
|
||||
label={label}
|
||||
placeholder={__('My content for this story...')}
|
||||
value={fileText}
|
||||
disabled={disabled}
|
||||
onChange={value => updatePublishForm({ fileText: advancedEditor ? value : value.target.value })}
|
||||
quickActionLabel={advancedEditor ? __('Simple Editor') : __('Advanced Editor')}
|
||||
quickActionHandler={toggleMarkdown}
|
||||
textAreaMaxLength={FF_MAX_CHARS_IN_DESCRIPTION}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default StoryEditor;
|
2
ui/constants/publish_types.js
Normal file
2
ui/constants/publish_types.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export const FILE = 'File';
|
||||
export const STORY = 'Story';
|
|
@ -251,7 +251,12 @@ svg + .button__label,
|
|||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
.button-tab-group {
|
||||
margin-bottom: var(--spacing-l);
|
||||
}
|
||||
|
||||
.button-group,
|
||||
.button-tab-group {
|
||||
display: flex;
|
||||
|
||||
.button:first-child:not(:only-child) {
|
||||
|
|
Loading…
Add table
Reference in a new issue