Publish revamp (Part 1) (#1593)

* Rearrange fields

* Autocomplete title

* Fix class position

* Hide deposit behind advanced settings

* Redesign additional options

* Redesign price section

* Update price section

* Redesign tags section

* Fix title edit

* Make with dynamic

* Redesign thumbnail section

* Redesign description section

* Resedign file section

* Polish sections

* Adjust help text

* Clear title on form reset

* Adjust price section

* Fix help color in light theme

* Polish

* Mobile adjustments

* More mobile adjustments

* Remove border-bottom from publish rows

* Redesign date section

* Adjust some details

* Adjust clear button

* Adjust channel selector on mobile

* Adjust post save button position

* Adjust browse button color

* Adjust channel picker on mobile

* Eenable announcement page

* Remove file title, remove space, redesign licence section

* Fix edit form, existing claim warning, missing title warning

* Adjust light theme

* Adjust icon collor in button
This commit is contained in:
Rave | 図書館猫 2022-06-03 15:28:12 +02:00 committed by GitHub
parent 9dc03d816a
commit 81eddb2b5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 806 additions and 451 deletions

View file

@ -78,7 +78,7 @@ class LicenseType extends React.PureComponent<Props> {
{licenseType === OTHER && (
<fieldset>
<legend>{__('Provide a description and link to your license')}</legend>
<div className="form-field__help">{__('Provide a description and link to your license')}</div>
<fieldset-group>
<FormField
label={__('License description')}

View file

@ -9,6 +9,7 @@ import LicenseType from './license-type';
import Card from 'component/common/card';
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import { sortLanguageMap } from 'util/default-languages';
import PublishBid from 'component/publishBid';
// @if TARGET='app'
// import ErrorText from 'component/common/error-text';
@ -39,6 +40,7 @@ function PublishAdditionalOptions(props: Props) {
licenseUrl,
updatePublishForm,
showSchedulingOptions,
disabled,
// user,
// useLBRYUploader,
// needsYTAuth,
@ -112,14 +114,20 @@ function PublishAdditionalOptions(props: Props) {
// @endif
return (
<Card
className="card--enable-overflow"
actions={
<React.Fragment>
{!hideSection && (
<div className={classnames({ 'card--disabled': !name })}>
{/* @if TARGET='app' */}
{/* {showLbryFirstCheckbox && (
<>
<h2 className="card__title">{__('Additional Options')}</h2>
<Card
className="card--enable-overflow card--publish-section card--additional-options"
actions={
<React.Fragment>
{!hideSection && (
<>
<div className="publish-row">
<PublishBid disabled={disabled} />
</div>
<div className={classnames({ 'card--disabled': !name })}>
{/* @if TARGET='app' */}
{/* {showLbryFirstCheckbox && (
<div className="section">
<>
<FormField
@ -152,55 +160,57 @@ function PublishAdditionalOptions(props: Props) {
</>
</div>
)} */}
{/* @endif */}
<div className="section">
{!showSchedulingOptions && <PublishReleaseDate />}
{/* @endif */}
<div className="section">
<div className="publish-row">{!showSchedulingOptions && <PublishReleaseDate />}</div>
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={(event) => updatePublishForm({ languages: [event.target.value] })}
>
{sortLanguageMap(SUPPORTED_LANGUAGES).map(([langKey, langName]) => (
<option key={langKey} value={langKey}>
{langName}
</option>
))}
</FormField>
<div className="publish-row">
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={(event) => updatePublishForm({ languages: [event.target.value] })}
>
{sortLanguageMap(SUPPORTED_LANGUAGES).map(([langKey, langName]) => (
<option key={langKey} value={langKey}>
{langName}
</option>
))}
</FormField>
</div>
<LicenseType
licenseType={licenseType}
otherLicenseDescription={otherLicenseDescription}
licenseUrl={licenseUrl}
handleLicenseChange={(newLicenseType, newLicenseUrl) =>
updatePublishForm({
licenseType: newLicenseType,
licenseUrl: newLicenseUrl,
})
}
handleLicenseDescriptionChange={(event) =>
updatePublishForm({
otherLicenseDescription: event.target.value,
})
}
handleLicenseUrlChange={(event) => updatePublishForm({ licenseUrl: event.target.value })}
/>
</div>
<div className="publish-row">
<LicenseType
licenseType={licenseType}
otherLicenseDescription={otherLicenseDescription}
licenseUrl={licenseUrl}
handleLicenseChange={(newLicenseType, newLicenseUrl) =>
updatePublishForm({
licenseType: newLicenseType,
licenseUrl: newLicenseUrl,
})
}
handleLicenseDescriptionChange={(event) =>
updatePublishForm({
otherLicenseDescription: event.target.value,
})
}
handleLicenseUrlChange={(event) => updatePublishForm({ licenseUrl: event.target.value })}
/>
</div>
</div>
</div>
</>
)}
<div className="section__actions">
<Button label={hideSection ? __('Show') : __('Hide')} button="link" onClick={toggleHideSection} />
</div>
)}
<div className="section__actions">
<Button
label={hideSection ? __('Additional Options') : __('Hide')}
button="link"
onClick={toggleHideSection}
/>
</div>
</React.Fragment>
}
/>
</React.Fragment>
}
/>
</>
);
}

View file

@ -20,26 +20,30 @@ function PublishDescription(props: Props) {
}
return (
<Card
actions={
<FormField
type={!SIMPLE_SITE && advancedEditor ? 'markdown' : 'textarea'}
name="content_description"
label={__('Description')}
placeholder={__(
'What is your content about? Use this space to include any other relevant details you may like to share about your content and channel.'
)}
value={description}
disabled={disabled}
onChange={value =>
updatePublishForm({ description: !SIMPLE_SITE && advancedEditor ? value : value.target.value })
}
quickActionLabel={!SIMPLE_SITE && (advancedEditor ? __('Simple Editor') : __('Advanced Editor'))}
quickActionHandler={toggleMarkdown}
textAreaMaxLength={FF_MAX_CHARS_IN_DESCRIPTION}
/>
}
/>
<>
{disabled && <h2 className="card__title card__title-disabled">{__('Description')}</h2>}
{!disabled && <h2 className="card__title">{__('Description')}</h2>}
<Card
className="card--description"
actions={
<FormField
type={!SIMPLE_SITE && advancedEditor ? 'markdown' : 'textarea'}
name="content_description"
placeholder={__(
'What is your content about? Use this space to include any other relevant details you may like to share about your content and channel.'
)}
value={description}
disabled={disabled}
onChange={(value) =>
updatePublishForm({ description: !SIMPLE_SITE && advancedEditor ? value : value.target.value })
}
quickActionLabel={!SIMPLE_SITE && (advancedEditor ? __('Simple Editor') : __('Advanced Editor'))}
quickActionHandler={toggleMarkdown}
textAreaMaxLength={FF_MAX_CHARS_IN_DESCRIPTION}
/>
}
/>
</>
);
}

View file

@ -149,6 +149,12 @@ function PublishFile(props: Props) {
}
}, [currentFileType, mode, isStillEditing, updatePublishForm]);
// Reset title when form gets cleared
useEffect(() => {
updatePublishForm({ title: title });
}, [filePath]);
// Initialize default file source state for each mode.
useEffect(() => {
setShowSourceSelector(false);
@ -365,9 +371,7 @@ function PublishFile(props: Props) {
}
function handleTitleChange(event) {
const title = event.target.value;
// Update title
updatePublishForm({ title });
updatePublishForm({ title: event.target.value });
}
function handleFileReaderLoaded(event: ProgressEvent) {
@ -430,6 +434,10 @@ function PublishFile(props: Props) {
updateFileInfo(0, file.size, isVideo);
}
// Strip off extention and replace invalid characters
let fileName = name || (file.name && file.name.substr(0, file.name.lastIndexOf('.'))) || '';
autofillTitle(file);
if (isTextPost) {
// Create reader
const reader = new FileReader();
@ -457,8 +465,6 @@ function PublishFile(props: Props) {
// File.path will be undefined from web due to browser security, so it will default to the File Object.
filePath: file.path || file,
};
// Strip off extention and replace invalid characters
let fileName = name || (file.name && file.name.substr(0, file.name.lastIndexOf('.'))) || '';
if (!isStillEditing) {
publishFormParams.name = parseName(fileName);
@ -469,12 +475,19 @@ function PublishFile(props: Props) {
updatePublishForm(publishFormParams);
}
function autofillTitle(file) {
const newTitle = (file && file.name && file.name.substr(0, file.name.lastIndexOf('.'))) || name || '';
if (!title) updatePublishForm({ title: newTitle });
}
const showFileUpload = mode === PUBLISH_MODES.FILE || PUBLISH_MODES.LIVESTREAM;
const isPublishPost = mode === PUBLISH_MODES.POST;
return (
<Card
className={disabled || balance === 0 ? 'card--disabled' : ''}
className={classnames({
'card--disabled': disabled || balance === 0,
})}
title={
<div>
{header} {/* display mode buttons from parent */}
@ -482,8 +495,8 @@ function PublishFile(props: Props) {
{inProgress && (
<div>
<Button
button="close"
label={__('New --[clears Publish Form]--')}
button="alt"
label={__('Clear --[clears Publish Form]--')}
icon={ICONS.REFRESH}
onClick={doClearPublish}
/>
@ -493,216 +506,227 @@ function PublishFile(props: Props) {
}
subtitle={subtitle || (isStillEditing && __('You are currently editing your upload.'))}
actions={
<React.Fragment>
<PublishName uri={uri} />
<FormField
type="text"
name="content_title"
label={__('Title')}
placeholder={__('Descriptive titles work best')}
disabled={disabled}
value={title}
onChange={handleTitleChange}
/>
{/* Decide whether to show file upload or replay selector */}
{/* @if TARGET='web' */}
<>
{showSourceSelector && (
<fieldset-section>
<div className="section__actions--between section__actions--align-bottom">
<div>
<label>{__('Replay video available')}</label>
<div className="button-group">
{fileSelectorModes.map((fmode) => (
<Button
key={fmode.label}
icon={fmode.icon || undefined}
iconSize={18}
label={fmode.label}
button="alt"
onClick={() => {
// $FlowFixMe
handleFileSource(fmode.actionName);
}}
className={classnames('button-toggle', {
'button-toggle--active': fileSource === fmode.actionName,
})}
/>
))}
</div>
</div>
{fileSource === SOURCE_SELECT && (
<Button
button="secondary"
label={__('Check for Replays')}
disabled={isCheckingLivestreams}
icon={ICONS.REFRESH}
onClick={() => checkLivestreams(channelId, channelName)}
/>
)}
</div>
</fieldset-section>
)}
{fileSource === SOURCE_UPLOAD && showFileUpload && (
<>
{/* <h2 className="card__title">{__('File')}</h2> */}
<div className="card--file">
<React.Fragment>
{/* Decide whether to show file upload or replay selector */}
{/* @if TARGET='web' */}
<>
{showSourceSelector && (
<fieldset-section>
<div className="section__actions--between section__actions--align-bottom">
<div>
<label>{__('Replay video available')}</label>
<div className="button-group">
{fileSelectorModes.map((fmode) => (
<Button
key={fmode.label}
icon={fmode.icon || undefined}
iconSize={18}
label={fmode.label}
button="alt"
onClick={() => {
// $FlowFixMe
handleFileSource(fmode.actionName);
}}
className={classnames('button-toggle', {
'button-toggle--active': fileSource === fmode.actionName,
})}
/>
))}
</div>
</div>
{fileSource === SOURCE_SELECT && (
<Button
button="secondary"
label={__('Check for Replays')}
disabled={isCheckingLivestreams}
icon={ICONS.REFRESH}
onClick={() => checkLivestreams(channelId, channelName)}
/>
)}
</div>
</fieldset-section>
)}
{fileSource === SOURCE_UPLOAD && showFileUpload && (
<>
<FileSelector
disabled={disabled}
currentPath={currentFile}
onFileChosen={handleFileChange}
// https://stackoverflow.com/questions/19107685/safari-input-type-file-accept-video-ignores-mp4-files
accept={SIMPLE_SITE ? 'video/mp4,video/x-m4v,video/*,audio/*' : undefined}
placeholder={
SIMPLE_SITE ? __('Select video or audio file to upload') : __('Select a file to upload')
}
/>
{getUploadMessage()}
</>
)}
{fileSource === SOURCE_SELECT && showFileUpload && hasLivestreamData && !isCheckingLivestreams && (
<>
<fieldset-section>
<label>{__('Select Replay')}</label>
<div className="table__wrapper">
<table className="table table--livestream-data">
<tbody>
{livestreamData
.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE)
.map((item, i) => (
<tr
onClick={() => setSelectedFileIndex((currentPage - 1) * PAGE_SIZE + i)}
key={item.id}
className={classnames('livestream__data-row', {
'livestream__data-row--selected':
selectedFileIndex === (currentPage - 1) * PAGE_SIZE + i,
})}
>
<td>
<FormField
type="radio"
checked={selectedFileIndex === (currentPage - 1) * PAGE_SIZE + i}
label={null}
onClick={() => setSelectedFileIndex((currentPage - 1) * PAGE_SIZE + i)}
className="livestream__data-row-radio"
/>
</td>
<td>
<div className="livestream_thumb_container">
{item.data.thumbnails.slice(0, 3).map((thumb) => (
<img key={thumb} className="livestream___thumb" src={thumb} />
))}
</div>
</td>
<td>
{item.data.fileDuration && isNaN(item.data.fileDuration)
? item.data.fileDuration
: `${Math.floor(item.data.fileDuration / 60)} ${
Math.floor(item.data.fileDuration / 60) > 1 ? __('minutes') : __('minute')
}`}
<div className="table__item-label">
{`${moment(item.data.uploadedAt).from(moment())}`}
</div>
</td>
<td>
<CopyableText
primaryButton
copyable={normalizeUrlForProtocol(item.data.fileLocation)}
snackMessage={__('Url copied.')}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
</fieldset-section>
<fieldset-group class="fieldset-group--smushed fieldgroup--paginate">
<fieldset-section>
<ReactPaginate
pageCount={totalPages}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={(e) => handlePaginateReplays(e.selected + 1)}
forcePage={currentPage - 1}
initialPage={currentPage - 1}
containerClassName="pagination"
/>
</fieldset-section>
</fieldset-group>
</>
)}
{fileSource === SOURCE_SELECT && showFileUpload && !hasLivestreamData && !isCheckingLivestreams && (
<div className="main--empty empty">
<Empty text={__('No replays found.')} />
</div>
)}
{fileSource === SOURCE_SELECT && showFileUpload && isCheckingLivestreams && (
<div className="main--empty empty">
<Spinner small />
</div>
)}
</>
<FormField
type="text"
name="content_title"
label={__('Title')}
placeholder={__('Descriptive titles work best')}
disabled={disabled}
value={title}
onChange={handleTitleChange}
className="fieldset-group"
/>
<PublishName uri={uri} />
{/* @endif */}
{/* @if TARGET='app' */}
{showFileUpload && (
<FileSelector
label={__('File')}
disabled={disabled}
currentPath={currentFile}
onFileChosen={handleFileChange}
// https://stackoverflow.com/questions/19107685/safari-input-type-file-accept-video-ignores-mp4-files
accept={SIMPLE_SITE ? 'video/mp4,video/x-m4v,video/*,audio/*' : undefined}
placeholder={SIMPLE_SITE ? __('Select video or audio file to upload') : __('Select a file to upload')}
placeholder={__('Select file to upload')}
/>
{getUploadMessage()}
</>
)}
{fileSource === SOURCE_SELECT && showFileUpload && hasLivestreamData && !isCheckingLivestreams && (
<>
<fieldset-section>
<label>{__('Select Replay')}</label>
<div className="table__wrapper">
<table className="table table--livestream-data">
<tbody>
{livestreamData.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE).map((item, i) => (
<tr
onClick={() => setSelectedFileIndex((currentPage - 1) * PAGE_SIZE + i)}
key={item.id}
className={classnames('livestream__data-row', {
'livestream__data-row--selected': selectedFileIndex === (currentPage - 1) * PAGE_SIZE + i,
})}
>
<td>
<FormField
type="radio"
checked={selectedFileIndex === (currentPage - 1) * PAGE_SIZE + i}
label={null}
onClick={() => setSelectedFileIndex((currentPage - 1) * PAGE_SIZE + i)}
className="livestream__data-row-radio"
/>
</td>
<td>
<div className="livestream_thumb_container">
{item.data.thumbnails.slice(0, 3).map((thumb) => (
<img key={thumb} className="livestream___thumb" src={thumb} />
))}
</div>
</td>
<td>
{item.data.fileDuration && isNaN(item.data.fileDuration)
? item.data.fileDuration
: `${Math.floor(item.data.fileDuration / 60)} ${
Math.floor(item.data.fileDuration / 60) > 1 ? __('minutes') : __('minute')
}`}
<div className="table__item-label">
{`${moment(item.data.uploadedAt).from(moment())}`}
</div>
</td>
<td>
<CopyableText
primaryButton
copyable={normalizeUrlForProtocol(item.data.fileLocation)}
snackMessage={__('Url copied.')}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
</fieldset-section>
<fieldset-group class="fieldset-group--smushed fieldgroup--paginate">
<fieldset-section>
<ReactPaginate
pageCount={totalPages}
pageRangeDisplayed={2}
previousLabel=""
nextLabel=""
activeClassName="pagination__item--selected"
pageClassName="pagination__item"
previousClassName="pagination__item pagination__item--previous"
nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2}
onPageChange={(e) => handlePaginateReplays(e.selected + 1)}
forcePage={currentPage - 1}
initialPage={currentPage - 1}
containerClassName="pagination"
/>
</fieldset-section>
</fieldset-group>
</>
)}
{fileSource === SOURCE_SELECT && showFileUpload && !hasLivestreamData && !isCheckingLivestreams && (
<div className="main--empty empty">
<Empty text={__('No replays found.')} />
</div>
)}
{fileSource === SOURCE_SELECT && showFileUpload && isCheckingLivestreams && (
<div className="main--empty empty">
<Spinner small />
</div>
)}
</>
{/* @endif */}
{/* @if TARGET='app' */}
{showFileUpload && (
<FileSelector
label={__('File')}
disabled={disabled}
currentPath={currentFile}
onFileChosen={handleFileChange}
// https://stackoverflow.com/questions/19107685/safari-input-type-file-accept-video-ignores-mp4-files
placeholder={__('Select file to upload')}
/>
)}
{showFileUpload && (
<FormField
type="checkbox"
checked={userOptimize}
disabled={!optimizeAvail}
onChange={() => setUserOptimize(!userOptimize)}
label={__('Optimize and transcode video')}
name="optimize"
/>
)}
{showFileUpload && !ffmpegAvail && (
<p className="help">
<I18nMessage
tokens={{
settings_link: <Button button="link" navigate="/$/settings" label={__('Settings')} />,
}}
>
FFmpeg not configured. More in %settings_link%.
</I18nMessage>
</p>
)}
{showFileUpload && Boolean(size) && ffmpegAvail && optimize && isVid && (
<p className="help">
<I18nMessage
tokens={{
size: Math.ceil(sizeInMB),
processTime: getTimeForMB(sizeInMB),
units: getUnitsForMB(sizeInMB),
}}
>
Transcoding this %size% MB file should take under %processTime% %units%.
</I18nMessage>
</p>
)}
{/* @endif */}
{isPublishPost && (
<PostEditor
label={__('Post --[noun, markdown post tab button]--')}
uri={uri}
disabled={disabled}
fileMimeType={fileMimeType}
setPrevFileText={setPrevFileText}
setCurrentFileType={setCurrentFileType}
/>
)}
</React.Fragment>
)}
{showFileUpload && (
<FormField
type="checkbox"
checked={userOptimize}
disabled={!optimizeAvail}
onChange={() => setUserOptimize(!userOptimize)}
label={__('Optimize and transcode video')}
name="optimize"
/>
)}
{showFileUpload && !ffmpegAvail && (
<p className="help">
<I18nMessage
tokens={{
settings_link: <Button button="link" navigate="/$/settings" label={__('Settings')} />,
}}
>
FFmpeg not configured. More in %settings_link%.
</I18nMessage>
</p>
)}
{showFileUpload && Boolean(size) && ffmpegAvail && optimize && isVid && (
<p className="help">
<I18nMessage
tokens={{
size: Math.ceil(sizeInMB),
processTime: getTimeForMB(sizeInMB),
units: getUnitsForMB(sizeInMB),
}}
>
Transcoding this %size% MB file should take under %processTime% %units%.
</I18nMessage>
</p>
)}
{/* @endif */}
{isPublishPost && (
<PostEditor
label={__('Post --[noun, markdown post tab button]--')}
uri={uri}
disabled={disabled}
fileMimeType={fileMimeType}
setPrevFileText={setPrevFileText}
setCurrentFileType={setCurrentFileType}
/>
)}
</React.Fragment>
</div>
</>
}
/>
);

View file

@ -20,7 +20,6 @@ import TagsSelect from 'component/tagsSelect';
import PublishDescription from 'component/publishDescription';
import PublishPrice from 'component/publishPrice';
import PublishFile from 'component/publishFile';
import PublishBid from 'component/publishBid';
import PublishAdditionalOptions from 'component/publishAdditionalOptions';
import PublishFormErrors from 'component/publishFormErrors';
import SelectThumbnail from 'component/selectThumbnail';
@ -593,7 +592,7 @@ function PublishForm(props: Props) {
// Editing claim uri
return (
<div className="card-stack uploadPage-wrapper">
<div className="card-stack">
<ChannelSelect hideAnon={isLivestreamMode} disabled={disabled} autoSet channelToSet={claimChannelId} />
<PublishFile
@ -635,15 +634,17 @@ function PublishForm(props: Props) {
}
/>
{mode !== PUBLISH_MODES.POST && <PublishDescription disabled={formDisabled} />}
{!publishing && (
<div className={classnames({ 'card--disabled': formDisabled })}>
{showSchedulingOptions && <Card body={<PublishStreamReleaseDate />} />}
{mode !== PUBLISH_MODES.POST && <PublishDescription disabled={formDisabled} />}
<Card actions={<SelectThumbnail livestreamData={livestreamData} />} />
<label style={{ marginTop: 'var(--spacing-l)' }}>{__('Tags')}</label>
<h2 className="card__title" style={{ marginTop: 'var(--spacing-l)' }}>
{__('Tags')}
</h2>
<TagsSelect
suggestMature={!SIMPLE_SITE}
disableAutoFocus
@ -671,7 +672,6 @@ function PublishForm(props: Props) {
tagsChosen={tags}
/>
<PublishBid disabled={isStillEditing || formDisabled} />
{!isLivestreamMode && <PublishPrice disabled={formDisabled} />}
<PublishAdditionalOptions disabled={formDisabled} showSchedulingOptions={showSchedulingOptions} />
@ -696,7 +696,7 @@ function PublishForm(props: Props) {
</div>
<p className="help">
{!formDisabled && !formValid ? (
<PublishFormErrors mode={mode} waitForFile={waitingForFile} overMaxBitrate={overMaxBitrate} />
<PublishFormErrors title={title} mode={mode} waitForFile={waitingForFile} overMaxBitrate={overMaxBitrate} />
) : (
<I18nMessage
tokens={{

View file

@ -72,13 +72,7 @@ function NameHelpText(props: Props) {
nameHelpText = <div className="error__text">{__('You already have a claim with this name.')}</div>;
}
return (
<React.Fragment>
{nameHelpText || (
<span>{__('Create a URL for this content. Simpler names are easier to find and remember.')}</span>
)}
</React.Fragment>
);
return <React.Fragment>{nameHelpText && nameHelpText}</React.Fragment>;
}
export default NameHelpText;

View file

@ -70,7 +70,7 @@ function PublishName(props: Props) {
<>
<fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section>
<label>{__('Name')}</label>
<label>{__('URL')}</label>
<div className="form-field__prefix">{prefix}</div>
</fieldset-section>
<FormField
@ -83,6 +83,7 @@ function PublishName(props: Props) {
onBlur={() => setBlurred(true)}
/>
</fieldset-group>
<div className="form-field__help">
<NameHelpText
uri={uri}

View file

@ -15,8 +15,9 @@ function PublishPrice(props: Props) {
return (
<>
<label>{__('Price')}</label>
<h2 className="card__title">{__('Price')}</h2>
<Card
className="card--publish-section card--price"
actions={
<React.Fragment>
<FormField

View file

@ -39,9 +39,11 @@ const PublishReleaseDate = (props: Props) => {
const isNew = releaseTime === undefined;
const isEdit = !isNew || allowDefault === false;
const showEditBtn = isNew && releaseTimeEdited === undefined && allowDefault !== false;
// const showEditBtn = isNew && releaseTimeEdited === undefined && allowDefault !== false;
const showEditBtn = false;
const showDefaultBtn = isNew && releaseTimeEdited !== undefined && allowDefault !== false;
const showDatePicker = isEdit || releaseTimeEdited !== undefined;
// const showDatePicker = isEdit || releaseTimeEdited !== undefined;
const showDatePicker = true;
const onDateTimePickerChanged = (value) => {
if (value) {

View file

@ -55,47 +55,50 @@ const PublishStreamReleaseDate = (props: Props) => {
);
return (
<div className="">
<label htmlFor="date-picker-input">{__('When do you want to go live?')}</label>
<>
<h2 className="card__title">{__('Date')}</h2>
<div className="card--date">
<label htmlFor="date-picker-input">{__('When do you want to go live?')}</label>
<div className={'w-full flex flex-col mt-s md:mt-0 md:h-12 md:items-center md:flex-row'}>
<FormField
type="radio"
name="anytime"
disabled={false}
onChange={handleToggle}
checked={!publishLater}
label={__('Anytime')}
/>
<div className={'md:ml-m mt-s md:mt-0'}>
<div className={'w-full flex flex-col mt-s md:mt-0 md:h-12 md:items-center md:flex-row'}>
<FormField
type="radio"
name="scheduled_time"
name="anytime"
disabled={false}
onChange={handleToggle}
checked={publishLater}
label={__('Scheduled Time')}
checked={!publishLater}
label={__('Anytime')}
/>
</div>
{publishLater && (
<div className="form-field-date-picker mb-0 controls md:ml-m">
<DateTimePicker
className="date-picker-input w-full md:w-auto mt-s md:mt-0"
calendarClassName="form-field-calendar"
onChange={onDateTimePickerChanged}
value={date}
format="y-MM-dd h:mm a"
disableClock
clearIcon={null}
minDate={moment().add('30', 'minutes').toDate()}
<div className={'md:ml-m mt-s md:mt-0'}>
<FormField
type="radio"
name="scheduled_time"
disabled={false}
onChange={handleToggle}
checked={publishLater}
label={__('Scheduled Time')}
/>
</div>
)}
</div>
{publishLater && (
<div className="form-field-date-picker mb-0 controls md:ml-m">
<DateTimePicker
className="date-picker-input w-full md:w-auto mt-s md:mt-0"
calendarClassName="form-field-calendar"
onChange={onDateTimePickerChanged}
value={date}
format="y-MM-dd h:mm a"
disableClock
clearIcon={null}
minDate={moment().add('30', 'minutes').toDate()}
/>
</div>
)}
</div>
<p className={'form-field__hint mt-m'}>{helpText}</p>
</div>
<p className={'form-field__hint mt-m'}>{helpText}</p>
</div>
</>
);
};

View file

@ -122,34 +122,35 @@ function SelectThumbnail(props: Props) {
return (
<>
<h2 className="card__title">{__('Thumbnail')}</h2>
{status !== THUMBNAIL_STATUSES.IN_PROGRESS && (
<>
<label>{__('Thumbnail')}</label>
<div className="column">
{thumbPreview}
{publishForm && thumbUploaded ? (
<div className="column__item">
<p>{__('Upload complete.')}</p>
<div className="section__actions">
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
</div>
<div className="column card--thumbnail">
{thumbPreview}
{publishForm && thumbUploaded ? (
<div className="column__item">
<p>{__('Upload complete.')}</p>
<div className="section__actions">
<Button button="link" label={__('New thumbnail')} onClick={resetThumbnailStatus} />
</div>
) : (
<div className="column__item">
{manualInput ? (
</div>
) : (
<div className="column__item">
{manualInput ? (
<>
<FormField
type="text"
name="content_thumbnail"
label="URL"
placeholder="https://images.fbi.gov/alien"
value={thumbnail}
disabled={formDisabled}
onChange={handleThumbnailChange}
/>
) : (
{!thumbUploaded && <p className="help">{__('Enter a URL for your thumbnail.')}</p>}
</>
) : (
<>
<FileSelector
currentPath={thumbnailPath}
label={__('Thumbnail')}
placeholder={__('Choose an enticing thumbnail')}
accept={accept}
onFileChosen={(file) =>
@ -159,44 +160,42 @@ function SelectThumbnail(props: Props) {
})
}
/>
)}
<div className="card__actions">
{!thumbUploaded && (
<p className="help">
{__('Upload your thumbnail to %domain%. Recommended ratio is 16:9, %max_size%MB max.', {
domain: DOMAIN,
max_size: THUMBNAIL_CDN_SIZE_LIMIT_BYTES / (1024 * 1024),
})}
</p>
)}
</>
)}
<div className="card__actions">
<Button
button="link"
label={manualInput ? __('Use thumbnail upload tool') : __('Enter a thumbnail URL')}
onClick={() =>
updatePublishForm({
uploadThumbnailStatus: manualInput ? THUMBNAIL_STATUSES.READY : THUMBNAIL_STATUSES.MANUAL,
})
}
/>
{status === THUMBNAIL_STATUSES.READY && isSupportedVideo && IS_WEB && (
// Disabled on desktop until this is resolved
// https://github.com/electron/electron/issues/20750#issuecomment-709505902
<Button
button="link"
label={manualInput ? __('Use thumbnail upload tool') : __('Enter a thumbnail URL')}
onClick={() =>
updatePublishForm({
uploadThumbnailStatus: manualInput ? THUMBNAIL_STATUSES.READY : THUMBNAIL_STATUSES.MANUAL,
})
}
label={__('Take a snapshot from your video')}
onClick={() => openModal(MODALS.AUTO_GENERATE_THUMBNAIL, { filePath: actualFilePath })}
/>
{status === THUMBNAIL_STATUSES.READY && isSupportedVideo && IS_WEB && (
// Disabled on desktop until this is resolved
// https://github.com/electron/electron/issues/20750#issuecomment-709505902
<Button
button="link"
label={__('Take a snapshot from your video')}
onClick={() => openModal(MODALS.AUTO_GENERATE_THUMBNAIL, { filePath: actualFilePath })}
/>
)}
</div>
)}
</div>
)}
</div>
</>
</div>
)}
</div>
)}
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
{!thumbUploaded && (
<p className="help">
{manualInput
? __('Enter a URL for your thumbnail.')
: __('Upload your thumbnail to %domain%. Recommended ratio is 16:9, %max_size%MB max.', {
domain: DOMAIN,
max_size: THUMBNAIL_CDN_SIZE_LIMIT_BYTES / (1024 * 1024),
})}
</p>
)}
</>
);
}

View file

@ -79,6 +79,7 @@ export default function TagsSelect(props: Props) {
return (
((showClose && !hasClosed) || !showClose) && (
<Card
className="card--tags"
icon={ICONS.TAG}
title={
hideHeader ? null : (

View file

@ -25,14 +25,7 @@ function PublishPage(props: Props) {
}
return (
<Page
noFooter
noSideNavigation
backout={{
title: __('Upload'),
backLabel: __('Back'),
}}
>
<Page className="uploadPage-wrapper" noFooter>
{balance === 0 && <YrblWalletEmpty />}
{balance !== 0 && fetchingChannels ? (
<div className="main--empty">

View file

@ -56,3 +56,12 @@
.spinnerArea--centered {
text-align: center;
}
.button--primary {
.spinner {
height: 30px;
.rect {
background-color: var(--color-primary-contrast);
}
}
}

View file

@ -425,6 +425,7 @@ img {
.error__text {
color: var(--color-text-error);
margin-left: 2px;
}
.help--error {
@ -480,8 +481,7 @@ img {
background-color: #fef1f6;
color: var(--color-black);
font-weight: bold;
.button {
help .button {
color: #fa6165;
}
}
@ -727,92 +727,397 @@ img {
}
.uploadPage-wrapper {
&.card-stack {
.card:not(:last-of-type) {
margin-bottom: var(--spacing-l) !important;
transition: width 0.4s;
@media (min-width: $breakpoint-small) {
width: 80% !important;
}
@media (min-width: $breakpoint-medium) {
width: 70% !important;
}
@media (min-width: $breakpoint-large) {
width: 60% !important;
}
@media (max-width: $breakpoint-small) {
.channel__selector {
margin-top: var(--spacing-m);
margin-bottom: var(--spacing-l);
button {
width: 100%;
.claim-preview__title {
// flex: 1;
text-align: left;
}
.comment__badge {
flex: 1;
text-align: left;
}
.icon--ChevronDown {
margin-left: auto;
}
}
}
}
.card__title-section {
width: 100%;
div:first-of-type:not(.card__subtitle) {
width: 100%;
}
h2 {
width: 100%;
div:first-of-type {
div {
width: unset !important;
float: right;
}
}
}
}
.card__header--between {
// margin-bottom: var(--spacing-xl);
margin-bottom: 0;
border-bottom: 1px solid var(--color-border);
@media (max-width: $breakpoint-small) {
margin-bottom: var(--spacing-l);
}
}
.card__title {
div {
display: inline-block;
margin-top: 0px;
right: 0;
}
.button {
margin-top: 0;
}
.button--alt:not(.button-toggle) {
font-size: var(--font-base);
}
}
.card__main-actions {
padding-top: var(--spacing-l);
border: unset;
}
label {
font-size: var(--font-medium);
font-size: var(--font-body);
}
.button--close {
&:hover {
color: var(--color-primary);
background-color: unset;
}
.form-field__prefix {
box-shadow: unset !important;
border-width: 2px 2px 2px 0 !important;
border-color: var(--color-border) !important;
background-color: var(--color-border) !important;
}
.icon__wrapper--Tag {
margin-right: var(--spacing-s) !important;
width: 1rem !important;
height: 1rem !important;
}
.card--publish-section {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
.card:not(:first-of-type) {
.card__main-actions:not(:first-of-type) {
border-top: unset;
}
.card__subtitle {
margin-top: 0 !important;
}
}
.card:nth-last-child(2) {
.card__main-actions {
padding-top: var(--spacing-xxxs);
fieldset-section:not(:first-child) {
margin-top: var(--spacing-s);
padding: 0;
}
fieldset-section {
padding: var(--spacing-s);
}
fieldset-section.radio {
margin-top: 0;
padding-bottom: 0;
}
fieldset-section.radio:last-of-type {
padding-bottom: var(--spacing-s);
}
fieldset-group {
margin-top: 0;
fieldset-section {
padding-right: 0;
}
.fieldset-group--smushed {
fieldset-section {
margin-top: 0;
label {
margin-left: 0;
}
.input--currency-select {
margin-left: 2px !important;
}
}
}
@media (max-width: $breakpoint-small) {
margin-top: var(--spacing-xxxs);
.input--currency-select {
padding-left: 2px;
}
}
.publish-row {
// border-bottom: 1px solid var(--color-border);
.form-field__help {
padding: var(--spacing-s);
padding-top: 0;
}
}
.form-field-date-picker {
padding: var(--spacing-s);
margin-bottom: 0;
}
}
.tags__input-wrapper {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
padding: var(--spacing-s);
}
.help {
opacity: 0.8;
margin-bottom: var(--spacing-l);
color: var(--color-text);
}
.form-field__two-column {
display: flex;
justify-content: space-between;
}
.comment__char-count-mde {
min-width: 40px;
text-align: center;
margin-bottom: var(--spacing-xxxs);
padding-left: 4px;
padding-right: 4px;
padding-top: 5px;
.card--file {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
height: var(--height-input-slim);
padding: var(--spacing-s);
input {
box-shadow: 0 0 0 2px var(--color-border) inset;
&:focus-visible {
box-shadow: 0 0 0 2px var(--color-primary) inset;
}
}
.button--secondary {
border-width: 2px 2px 2px 0;
border-color: var(--color-primary);
background-color: var(--color-primary) !important;
.icon {
stroke: var(--color-primary-contrast) !important;
}
.button__label {
color: var(--color-primary-contrast) !important;
}
}
label {
margin-left: 0 !important;
}
}
.section__actions {
.button {
.button__content {
.button__label {
margin-top: 0;
.card__title-disabled {
opacity: 0.3;
}
.card--description {
label {
font-size: var(--font-large);
font-weight: var(--font-weight-bold);
}
.card__main-actions {
padding-top: 0;
margin-top: 0;
}
.MuiAutocomplete-root {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
padding: var(--spacing-s);
textarea {
box-shadow: 0 0 0 2px var(--color-border) inset;
&:focus-visible {
box-shadow: 0 0 0 2px var(--color-primary) inset;
}
}
@media (max-width: $breakpoint-small) {
.MuiFormControl-root {
border-radius: var(--border-radius);
box-shadow: 0 0 0 2px var(--color-border) inset;
}
textarea {
box-shadow: unset;
}
}
}
}
.card--thumbnail {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
padding: var(--spacing-s);
input {
box-shadow: 0 0 0 2px var(--color-border) inset;
}
.button--secondary {
border-width: 2px 2px 2px 0;
border-color: var(--color-primary);
background-color: var(--color-primary) !important;
.icon {
stroke: var(--color-primary-contrast) !important;
}
.button__label {
color: var(--color-primary-contrast) !important;
}
}
@media (max-width: $breakpoint-small) {
.thumbnail-picker__preview {
width: 100%;
height: unset;
aspect-ratio: 16 / 9;
}
.column__item:last-of-type {
margin-bottom: 0;
}
}
}
.card--tags {
input {
box-shadow: 0 0 0 2px var(--color-border) inset;
}
.icon__wrapper {
margin-right: var(--spacing-s) !important;
}
.card__subtitle {
margin-top: 5px;
}
.card__main-actions {
padding-top: 0;
border-top: unset;
}
.card__header--between {
margin-bottom: unset;
border: unset;
}
.tag {
background-color: var(--color-header-button);
}
@media (max-width: $breakpoint-small) {
.card__subtitle {
font-size: var(--font-small);
}
}
}
.card--price {
.input--currency-select {
label {
margin-left: 0 !important;
}
}
.form-field--price-amount,
select {
box-shadow: 0 0 0 2px var(--color-border) inset;
}
@media (max-width: $breakpoint-small) {
.card__main-actions {
margin-top: 0;
}
}
}
.card--additional-options {
margin-bottom: var(--spacing-l) !important;
.card {
fieldset-section {
padding-bottom: 0;
}
}
.card__main-actions {
//padding-top:var(--spacing-s);
padding-top: 0;
}
.section__actions {
padding: var(--spacing-s);
margin-top: 0;
}
input,
select {
box-shadow: 0 0 0 2px var(--color-border) inset;
&:focus-visible {
box-shadow: 0 0 0 2px var(--color-primary) inset;
}
}
.react-datetime-picker {
box-shadow: 0 0 0 2px var(--color-border) inset;
input {
box-shadow: unset;
}
.react-datetime-picker__inputGroup__amPm {
margin-top: 4px;
height: calc(100% - 8px);
box-shadow: unset;
&:focus-visible {
box-shadow: 0 0 0 2px var(--color-primary) inset;
}
}
}
.form-field__help {
margin-bottom: 0;
}
fieldset {
.form-field__help {
margin-top: 0;
}
}
fieldset-section {
margin-top: 0;
}
fieldset-group {
fieldset-section {
width: 50%;
&:last-of-type {
padding-right: var(--spacing-s);
}
}
}
@media (max-width: $breakpoint-small) {
button {
margin-bottom: 0;
}
border-top: unset;
}
}
.card--date {
background: rgba(var(--color-header-background-base), 0.4);
border-radius: var(--border-radius);
padding: var(--spacing-s);
.form-field__hint {
opacity: 0.8;
// margin-bottom: var(--spacing-l);
color: var(--color-text);
}
.react-datetime-picker {
box-shadow: 0 0 0 2px var(--color-border) inset;
input {
box-shadow: unset;
}
.react-datetime-picker__inputGroup__amPm {
margin-top: 4px;
height: calc(100% - 8px);
box-shadow: unset;
&:focus-visible {
box-shadow: 0 0 0 2px var(--color-primary) inset;
}
}
}
}
.EasyMDEContainer {
.editor-toolbar,
.CodeMirror-wrap {
border-width: 2px !important;
}
.editor-statusbar {
padding: 0;
padding-top: var(--spacing-s);
}
}
@ -842,6 +1147,13 @@ img {
}
}
[data-reach-menu-popover] {
@media (max-width: $breakpoint-small) {
width: calc(100% - var(--spacing-xs) * 2);
max-width: calc(100% - var(--spacing-xs) * 2);
}
}
.transactionsPage-wrapper {
.card__header--between {
align-items: unset;

View file

@ -80,6 +80,7 @@
--color-input-label: var(--color-text);
--color-input-placeholder: #f4f4f5;
--color-input-bg: var(--color-header-background);
--color-input-bg-secondary: #333333;
--color-input-bg-selected: var(--color-primary);
--color-input-border: var(--color-border);
--color-input-toggle: var(--color-primary-alt-3);

View file

@ -88,6 +88,7 @@
--color-input-label: var(--color-text);
--color-input-placeholder: #212529;
--color-input-bg: var(--color-header-background);
--color-input-bg-secondary: #ffffff;
--color-input-bg-selected: var(--color-primary);
--color-input-border: var(--color-border);
--color-input-toggle: var(--color-secondary);