separate out advanced textarea, fix comment channel selector width, a… (#7634)

* separate out advanced textarea, fix comment channel selector width, add advanced text icon

* fix master conflicts

* fixes

* fix channel description edit
This commit is contained in:
jessopb 2022-11-04 08:42:36 -04:00 committed by GitHub
parent ae1e20d131
commit 35769dede6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 386 additions and 210 deletions

View file

@ -2319,5 +2319,7 @@
"Your hub has blocked this content because it subscribes to the following blocking channel:": "Your hub has blocked this content because it subscribes to the following blocking channel:",
"Your hub has blocked access to this content do to a complaint received under the US Digital Millennium Copyright Act.": "Your hub has blocked access to this content do to a complaint received under the US Digital Millennium Copyright Act.",
"Autoplay Next is on.": "Autoplay Next is on.",
"This will be visible in a few minutes after you submit this form.": "This will be visible in a few minutes after you submit this form.",
"Anon --[used in <%anonymous% Reposted>]--": "Anon",
"--end--": "--end--"
}

View file

@ -3,7 +3,7 @@ import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons';
import React from 'react';
import classnames from 'classnames';
import { FormField } from 'component/common/form';
import { FormField, FormFieldAreaAdvanced } from 'component/common/form';
import Button from 'component/button';
import TagsSearch from 'component/tagsSearch';
import ErrorText from 'component/common/error-text';
@ -376,7 +376,7 @@ function ChannelForm(props: Props) {
onChange={(e) => setParams({ ...params, title: e.target.value })}
maxLength={MAX_TITLE_LEN}
/>
<FormField
<FormFieldAreaAdvanced
type="markdown"
name="content_description2"
label={__('Description')}

View file

@ -17,7 +17,7 @@ import { useHistory } from 'react-router-dom';
import { isNameValid, regexInvalidURI } from 'util/lbryURI';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs';
import { FormField } from 'component/common/form';
import { FormField, FormFieldAreaAdvanced } from 'component/common/form';
import { handleBidChange } from 'util/publish';
import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field';
import { INVALID_NAME_ERROR } from 'constants/claim';
@ -371,7 +371,7 @@ function CollectionForm(props: Props) {
usePublishFormMode
/>
</fieldset-section>
<FormField
<FormFieldAreaAdvanced
type="markdown"
name="content_description2"
label={__('Description')}

View file

@ -17,7 +17,7 @@ import CommentBadge from 'component/common/comment-badge'; // have this?
import ChannelThumbnail from 'component/channelThumbnail';
import { Menu, MenuButton } from '@reach/menu-button';
import Icon from 'component/common/icon';
import { FormField, Form } from 'component/common/form';
import { FormFieldAreaAdvanced, Form } from 'component/common/form';
import classnames from 'classnames';
import usePersistedState from 'effects/use-persisted-state';
import CommentReactions from 'component/commentReactions';
@ -319,7 +319,7 @@ function CommentView(props: Props) {
<div>
{isEditing ? (
<Form onSubmit={handleSubmit}>
<FormField
<FormFieldAreaAdvanced
className="comment__edit-input"
type={advancedEditor ? 'markdown' : 'textarea'}
name="editing_comment"

View file

@ -0,0 +1,32 @@
// @flow
import React from 'react';
import SelectChannel from 'component/selectChannel';
import Button from 'component/button';
import * as ICONS from 'constants/icons';
type Props = {
isReply: boolean,
advancedHandler: () => void,
advanced: boolean,
};
export default function CommentCreateHeader(props: Props) {
const { isReply, advancedHandler, advanced } = props;
return (
<div className="comment-create__header">
<div className="comment-create__label-wrapper">
<span className="comment-create__label">{(isReply ? __('Replying as') : __('Comment as')) + ' '}</span>
<SelectChannel tiny />
</div>
<div className="form-field__quick-action">
<Button
button="alt"
icon={advanced ? ICONS.SIMPLE_EDITOR : ICONS.ADVANCED_EDITOR}
onClick={advancedHandler}
aria-label={isReply ? undefined : advanced ? __('Simple Editor') : __('Advanced Editor')}
/>
</div>
</div>
);
}

View file

@ -4,7 +4,7 @@ import 'scss/component/_comment-create.scss';
import { buildValidSticker } from 'util/comments';
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
import { FormField, Form } from 'component/common/form';
import { FormFieldAreaAdvanced, Form } from 'component/common/form';
import { getChannelIdFromClaim } from 'util/claim';
import { Lbryio } from 'lbryinc';
import { useHistory } from 'react-router';
@ -22,8 +22,8 @@ import I18nMessage from 'component/i18nMessage';
import Icon from 'component/common/icon';
import OptimizedImage from 'component/optimizedImage';
import React from 'react';
import SelectChannel from 'component/selectChannel';
import StickerSelector from './sticker-selector';
import CommentCreateHeader from './comment-create-header';
import type { ElementRef } from 'react';
import UriIndicator from 'component/uriIndicator';
import usePersistedState from 'effects/use-persisted-state';
@ -409,7 +409,11 @@ export function CommentCreate(props: Props) {
push(pathPlusRedirect);
}}
>
<FormField type="textarea" name={'comment_signup_prompt'} placeholder={__('Say something about this...')} />
<FormFieldAreaAdvanced
type="textarea"
name={'comment_signup_prompt'}
placeholder={__('Say something about this...')}
/>
<div className="section__actions--no-margin">
<Button disabled button="primary" label={__('Post --[button to submit something]--')} />
</div>
@ -420,22 +424,22 @@ export function CommentCreate(props: Props) {
return (
<Form
onSubmit={() => {}}
className={classnames('commentCreate', {
'commentCreate--reply': isReply,
'commentCreate--nestedReply': isNested,
'commentCreate--bottom': bottom,
className={classnames('comment-create', {
'comment-create--reply': isReply,
'comment-create--nestedReply': isNested,
'comment-create--bottom': bottom,
})}
>
{/* Input Box/Preview Box */}
{stickerSelector ? (
<StickerSelector onSelect={(sticker) => handleSelectSticker(sticker)} claimIsMine={claimIsMine} />
) : isReviewingStickerComment && activeChannelClaim && selectedSticker ? (
<div className="commentCreate__stickerPreview">
<div className="commentCreate__stickerPreviewInfo">
<div className="comment-create__stickerPreview">
<div className="comment-create__stickerPreviewInfo">
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
<UriIndicator uri={activeChannelClaim.canonical_url} link />
</div>
<div className="commentCreate__stickerPreviewImage">
<div className="comment-create__stickerPreviewImage">
<OptimizedImage src={selectedSticker && selectedSticker.url} waitLoad loading="lazy" />
</div>
{/* figure out lbc sticker prices */}
@ -447,15 +451,15 @@ export function CommentCreate(props: Props) {
)}
</div>
) : isReviewingSupportComment && activeChannelClaim ? (
<div className="commentCreate__supportCommentPreview">
<div className="comment-create__supportCommentPreview">
<CreditAmount
amount={tipAmount}
className="commentCreate__supportCommentPreviewAmount"
className="comment-create__supportCommentPreviewAmount"
isFiat={activeTab === TAB_FIAT}
size={activeTab === TAB_LBC ? 18 : 2}
/>
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
<div className="commentCreate__supportCommentBody">
<div className="comment-create__supportCommentBody">
<UriIndicator uri={activeChannelClaim.canonical_url} link />
<div>{commentValue}</div>
</div>
@ -470,23 +474,22 @@ export function CommentCreate(props: Props) {
/>
)}
<FormField
<FormFieldAreaAdvanced
autoFocus={isReply}
charCount={charCount}
className={isReply ? 'content_reply' : 'content_comment'}
disabled={isFetchingChannels}
label={
<div className="commentCreate__labelWrapper">
<span className="commentCreate__label">{(isReply ? __('Replying as') : __('Comment as')) + ' '}</span>
<SelectChannel tiny />
</div>
header={
<CommentCreateHeader
isReply={isReply}
advanced={advancedEditor}
advancedHandler={() => setAdvancedEditor(!advancedEditor)}
/>
}
name={isReply ? 'content_reply' : 'content_description'}
quickActionLabel={isReply ? undefined : advancedEditor ? __('Simple Editor') : __('Advanced Editor')}
ref={formFieldRef}
onChange={handleCommentChange}
openEmoteMenu={() => setShowEmotes(!showEmotes)}
quickActionHandler={() => setAdvancedEditor(!advancedEditor)}
onFocus={onTextareaFocus}
onBlur={onTextareaBlur}
placeholder={__('Say something about this...')}
@ -654,7 +657,7 @@ export function CommentCreate(props: Props) {
{/* Help Text */}
{deletedComment && <div className="error__text">{__('This comment has been deleted.')}</div>}
{!!minAmount && (
<div className="help--notice commentCreate__minAmountNotice">
<div className="help--notice comment-create__minAmountNotice">
<I18nMessage tokens={{ lbc: <CreditAmount noFormat amount={minAmount} /> }}>
{minTip ? 'Comment min: %lbc%' : minSuper ? 'HyperChat min: %lbc%' : ''}
</I18nMessage>

View file

@ -383,7 +383,7 @@ const CommentActionButtons = (actionButtonsProps: ActionButtonsProps) => {
<Button button="alt" icon={ICONS.REFRESH} title={__('Refresh')} onClick={() => setPage(0)} />
</div>
{allServers.length >= 2 && (
<div className="button_selectedServer">
<div className="button__selected-server">
<FormField
type="select-tiny"
onChange={function (x) {

View file

@ -0,0 +1,240 @@
// @flow
import 'easymde/dist/easymde.min.css';
import { FF_MAX_CHARS_DEFAULT } from 'constants/form-field';
import { openEditorMenu, stopContextMenu } from 'util/context-menu';
import * as ICONS from 'constants/icons';
import Button from 'component/button';
import MarkdownPreview from 'component/common/markdown-preview';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import SimpleMDE from 'react-simplemde-editor';
import TextareaWithSuggestions from 'component/textareaWithSuggestions';
import type { ElementRef, Node } from 'react';
type Props = {
autoFocus?: boolean,
blockWrap: boolean,
charCount?: number,
children?: React$Node,
disabled?: boolean,
helper?: string | React$Node,
hideSuggestions?: boolean,
isLivestream?: boolean,
label?: string | Node,
labelOnLeft: boolean,
name: string,
noEmojis?: boolean,
placeholder?: string | number,
quickActionLabel?: string,
textAreaMaxLength?: number,
type?: string,
value?: string | number,
onChange?: (any) => any,
openEmoteMenu?: () => void,
quickActionHandler?: (any) => any,
render?: () => React$Node,
header?: React$Node,
};
export class FormFieldAreaAdvanced extends React.PureComponent<Props> {
static defaultProps = { labelOnLeft: false, blockWrap: true };
input: { current: ElementRef<any> };
constructor(props: Props) {
super(props);
this.input = React.createRef();
}
componentDidMount() {
const { autoFocus } = this.props;
const input = this.input.current;
if (input && autoFocus) input.focus();
}
render() {
const {
autoFocus,
blockWrap,
charCount,
children,
helper,
hideSuggestions,
isLivestream,
label,
header,
labelOnLeft,
name,
noEmojis,
quickActionLabel,
textAreaMaxLength,
type,
openEmoteMenu,
quickActionHandler,
render,
...inputProps
} = this.props;
// Ideally, the character count should (and can) be appended to the
// SimpleMDE's "options::status" bar. However, I couldn't figure out how
// to pass the current value to it's callback, nor query the current
// text length from the callback. So, we'll use our own widget.
const hasCharCount = charCount !== undefined && charCount >= 0;
const countInfo = hasCharCount && textAreaMaxLength !== undefined && (
<span className="comment__char-count-mde">{`${charCount || '0'}/${textAreaMaxLength}`}</span>
);
const quickAction =
quickActionLabel && quickActionHandler ? (
<div className="form-field__quick-action">
<Button button="link" onClick={quickActionHandler} label={quickActionLabel} />
</div>
) : null;
const input = () => {
switch (type) {
case 'markdown':
const handleEvents = { contextmenu: openEditorMenu };
const getInstance = (editor) => {
// SimpleMDE max char check
editor.codemirror.on('beforeChange', (instance, changes) => {
if (textAreaMaxLength && changes.update) {
var str = changes.text.join('\n');
var delta = str.length - (instance.indexFromPos(changes.to) - instance.indexFromPos(changes.from));
if (delta <= 0) return;
delta = instance.getValue().length + delta - textAreaMaxLength;
if (delta > 0) {
str = str.substring(0, str.length - delta);
changes.update(changes.from, changes.to, str.split('\n'));
}
}
});
// "Create Link (Ctrl-K)": highlight URL instead of label:
editor.codemirror.on('changes', (instance, changes) => {
try {
// Grab the last change from the buffered list. I assume the
// buffered one ('changes', instead of 'change') is more efficient,
// and that "Create Link" will always end up last in the list.
const lastChange = changes[changes.length - 1];
if (lastChange.origin === '+input') {
// https://github.com/Ionaru/easy-markdown-editor/blob/8fa54c496f98621d5f45f57577ce630bee8c41ee/src/js/easymde.js#L765
const EASYMDE_URL_PLACEHOLDER = '(https://)';
// The URL placeholder is always placed last, so just look at the
// last text in the array to also cover the multi-line case:
const urlLineText = lastChange.text[lastChange.text.length - 1];
if (urlLineText.endsWith(EASYMDE_URL_PLACEHOLDER) && urlLineText !== '[]' + EASYMDE_URL_PLACEHOLDER) {
const from = lastChange.from;
const to = lastChange.to;
const isSelectionMultiline = lastChange.text.length > 1;
const baseIndex = isSelectionMultiline ? 0 : from.ch;
// Everything works fine for the [Ctrl-K] case, but for the
// [Button] case, this handler happens before the original
// code, thus our change got wiped out.
// Add a small delay to handle that case.
setTimeout(() => {
instance.setSelection(
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf('(') + 1 },
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf(')') }
);
}, 25);
}
}
} catch (e) {} // Do nothing (revert to original behavior)
});
};
return (
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
<fieldset-section>
{!header && (
<div className="form-field__two-column">
<div>
<label htmlFor={name}>{label}</label>
</div>
{quickAction}
</div>
)}
{!!header && <div className="form-field__textarea-header">{header}</div>}
<SimpleMDE
{...inputProps}
id={name}
type="textarea"
events={handleEvents}
getMdeInstance={getInstance}
options={{
spellChecker: true,
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} noDataStore />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
{countInfo}
</fieldset-section>
</div>
);
case 'textarea':
return (
<fieldset-section>
{!header && (label || quickAction) && (
<div className="form-field__two-column">
<label htmlFor={name}>{label}</label>
{quickAction}
</div>
)}
{!!header && <div className="form-field__textarea-header">{header}</div>}
{hideSuggestions ? (
<textarea
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
ref={this.input}
{...inputProps}
/>
) : (
<TextareaWithSuggestions
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
inputRef={this.input}
isLivestream={isLivestream}
{...inputProps}
/>
)}
<div className="form-field__textarea-info">
{!noEmojis && openEmoteMenu && (
<Button
type="alt"
className="button--comment-icons"
title="Emotes"
onClick={openEmoteMenu}
icon={ICONS.EMOJI}
iconSize={20}
/>
)}
{countInfo}
</div>
</fieldset-section>
);
}
};
return (
<>
{type && input()}
{helper && <div className="form-field__help">{helper}</div>}
</>
);
}
}
export default FormFieldAreaAdvanced;

View file

@ -1,14 +1,7 @@
// @flow
import 'easymde/dist/easymde.min.css';
import { FF_MAX_CHARS_DEFAULT } from 'constants/form-field';
import { openEditorMenu, stopContextMenu } from 'util/context-menu';
import * as ICONS from 'constants/icons';
import Button from 'component/button';
import MarkdownPreview from 'component/common/markdown-preview';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import SimpleMDE from 'react-simplemde-editor';
import TextareaWithSuggestions from 'component/textareaWithSuggestions';
import type { ElementRef, Node } from 'react';
type Props = {
@ -21,19 +14,15 @@ type Props = {
disabled?: boolean,
error?: string | boolean,
helper?: string | React$Node,
hideSuggestions?: boolean,
inputButton?: React$Node,
isLivestream?: boolean,
label?: string | Node,
labelOnLeft: boolean,
max?: number,
min?: number,
name: string,
noEmojis?: boolean,
placeholder?: string | number,
postfix?: string,
prefix?: string,
quickActionLabel?: string,
range?: number,
readOnly?: boolean,
stretch?: boolean,
@ -41,8 +30,6 @@ type Props = {
type?: string,
value?: string | number,
onChange?: (any) => any,
openEmoteMenu?: () => void,
quickActionHandler?: (any) => any,
render?: () => React$Node,
};
@ -72,21 +59,15 @@ export class FormField extends React.PureComponent<Props> {
children,
error,
helper,
hideSuggestions,
inputButton,
isLivestream,
label,
labelOnLeft,
name,
noEmojis,
postfix,
prefix,
quickActionLabel,
stretch,
textAreaMaxLength,
type,
openEmoteMenu,
quickActionHandler,
render,
...inputProps
} = this.props;
@ -101,18 +82,10 @@ export class FormField extends React.PureComponent<Props> {
const countInfo = hasCharCount && textAreaMaxLength !== undefined && (
<span className="comment__char-count-mde">{`${charCount || '0'}/${textAreaMaxLength}`}</span>
);
const Wrapper = blockWrap
? ({ children: innerChildren }) => <fieldset-section class="radio">{innerChildren}</fieldset-section>
: ({ children: innerChildren }) => <span className="radio">{innerChildren}</span>;
const quickAction =
quickActionLabel && quickActionHandler ? (
<div className="form-field__quick-action">
<Button button="link" onClick={quickActionHandler} label={quickActionLabel} />
</div>
) : null;
const inputSimple = (type: string) => (
<>
<input id={name} type={type} {...inputProps} />
@ -143,133 +116,22 @@ export class FormField extends React.PureComponent<Props> {
return inputSelect('');
case 'select-tiny':
return inputSelect('select--slim');
case 'markdown':
const handleEvents = { contextmenu: openEditorMenu };
const getInstance = (editor) => {
// SimpleMDE max char check
editor.codemirror.on('beforeChange', (instance, changes) => {
if (textAreaMaxLength && changes.update) {
var str = changes.text.join('\n');
var delta = str.length - (instance.indexFromPos(changes.to) - instance.indexFromPos(changes.from));
if (delta <= 0) return;
delta = instance.getValue().length + delta - textAreaMaxLength;
if (delta > 0) {
str = str.substring(0, str.length - delta);
changes.update(changes.from, changes.to, str.split('\n'));
}
}
});
// "Create Link (Ctrl-K)": highlight URL instead of label:
editor.codemirror.on('changes', (instance, changes) => {
try {
// Grab the last change from the buffered list. I assume the
// buffered one ('changes', instead of 'change') is more efficient,
// and that "Create Link" will always end up last in the list.
const lastChange = changes[changes.length - 1];
if (lastChange.origin === '+input') {
// https://github.com/Ionaru/easy-markdown-editor/blob/8fa54c496f98621d5f45f57577ce630bee8c41ee/src/js/easymde.js#L765
const EASYMDE_URL_PLACEHOLDER = '(https://)';
// The URL placeholder is always placed last, so just look at the
// last text in the array to also cover the multi-line case:
const urlLineText = lastChange.text[lastChange.text.length - 1];
if (urlLineText.endsWith(EASYMDE_URL_PLACEHOLDER) && urlLineText !== '[]' + EASYMDE_URL_PLACEHOLDER) {
const from = lastChange.from;
const to = lastChange.to;
const isSelectionMultiline = lastChange.text.length > 1;
const baseIndex = isSelectionMultiline ? 0 : from.ch;
// Everything works fine for the [Ctrl-K] case, but for the
// [Button] case, this handler happens before the original
// code, thus our change got wiped out.
// Add a small delay to handle that case.
setTimeout(() => {
instance.setSelection(
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf('(') + 1 },
{ line: to.line, ch: baseIndex + urlLineText.lastIndexOf(')') }
);
}, 25);
}
}
} catch (e) {} // Do nothing (revert to original behavior)
});
};
return (
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
<fieldset-section>
<div className="form-field__two-column">
<div>
<label htmlFor={name}>{label}</label>
</div>
{quickAction}
</div>
<SimpleMDE
{...inputProps}
id={name}
type="textarea"
events={handleEvents}
getMdeInstance={getInstance}
options={{
spellChecker: true,
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
previewRender(plainText) {
const preview = <MarkdownPreview content={plainText} noDataStore />;
return ReactDOMServer.renderToString(preview);
},
}}
/>
{countInfo}
</fieldset-section>
</div>
);
case 'textarea':
return (
<fieldset-section>
{(label || quickAction) && (
{label && (
<div className="form-field__two-column">
<label htmlFor={name}>{label}</label>
{quickAction}
</div>
)}
{hideSuggestions ? (
<textarea
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
ref={this.input}
{...inputProps}
/>
) : (
<TextareaWithSuggestions
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
inputRef={this.input}
isLivestream={isLivestream}
{...inputProps}
/>
)}
<div className="form-field__textarea-info">
{!noEmojis && openEmoteMenu && (
<Button
type="alt"
className="button--comment-icons"
title="Emotes"
onClick={openEmoteMenu}
icon={ICONS.EMOJI}
iconSize={20}
/>
)}
{countInfo}
</div>
<textarea
type={type}
id={name}
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
ref={this.input}
{...inputProps}
/>
<div className="form-field__textarea-info">{countInfo}</div>
</fieldset-section>
);
default:

View file

@ -1,4 +1,5 @@
export { Form } from './form-components/form';
export { FormField } from './form-components/form-field';
export { FormFieldAreaAdvanced } from './form-components/form-field-area-advanced';
export { FormFieldPrice } from './form-components/form-field-price';
export { Submit } from './form-components/submit';

View file

@ -2054,4 +2054,15 @@ export const icons = {
<path d="M12.5,23.24v-1A10.74,10.74,0,0,1,23.24,11.52" />
</g>
),
[ICONS.SIMPLE_EDITOR]: buildIcon(
<g>
<path d="M1 18V6c0-1 1-2 2-2h18c1 0 2 1 2 2v12c0 1-1 2-2 2H3c-1 0-2-1-2-2ZM5 7v4" />
</g>
),
[ICONS.ADVANCED_EDITOR]: buildIcon(
<g>
<path d="M1 20V4c0-1 1-2 2-2h18c1 0 2 1 2 2v16c0 1-1 2-2 2H3c-1 0-2-1-2-2ZM1 11h22" />
<path d="M5 8V6h2v2H5ZM11 8V6h2v2h-2ZM17 8V6h2v2h-2ZM5 14v4" />
</g>
),
};

View file

@ -1,6 +1,6 @@
// @flow
import React, { useEffect } from 'react';
import { FormField } from 'component/common/form';
import { FormFieldAreaAdvanced } from 'component/common/form';
type Props = {
uri: ?string,
@ -99,7 +99,7 @@ function PostEditor(props: Props) {
]);
return (
<FormField
<FormFieldAreaAdvanced
type={'markdown'}
name="content_post"
label={label}

View file

@ -1,7 +1,7 @@
// @flow
import { FF_MAX_CHARS_IN_DESCRIPTION } from 'constants/form-field';
import React from 'react';
import { FormField } from 'component/common/form';
import { FormFieldAreaAdvanced } from 'component/common/form';
import usePersistedState from 'effects/use-persisted-state';
import Card from 'component/common/card';
@ -27,7 +27,7 @@ function PublishDescription(props: Props) {
return (
<Card
actions={
<FormField
<FormFieldAreaAdvanced
type={advancedEditor ? 'markdown' : 'textarea'}
name="content_description"
label={__('Description')}

View file

@ -186,3 +186,5 @@ export const MYSTERIES = 'Mysteries';
export const TECHNOLOGY = 'Technology';
export const EMOJI = 'Emoji';
export const STICKER = 'Sticker';
export const SIMPLE_EDITOR = 'SimpleEditor';
export const ADVANCED_EDITOR = 'AdvancedEditor';

View file

@ -62,7 +62,7 @@ class ReportPage extends React.Component {
name="message"
stretch
value={this.state.message}
onChange={event => {
onChange={(event) => {
this.onMessageChange(event);
}}
placeholder={__('Description of your issue or feature request')}
@ -71,7 +71,7 @@ class ReportPage extends React.Component {
<div className="section__actions">
<Button
button="primary"
onClick={event => {
onClick={(event) => {
this.submitMessage(event);
}}
className={`button-block button-primary ${this.state.submitting ? 'disabled' : ''}`}

View file

@ -41,7 +41,7 @@
margin: 0px var(--spacing-xxs);
}
.button + .commentCreate {
.button + .comment-create {
margin-top: var(--spacing-xxs);
}
}
@ -659,7 +659,7 @@
}
}
.button_selectedServer {
.button__selected-server {
display: inline;
float: right;
select {

View file

@ -7,7 +7,7 @@ $thumbnailWidthSmall: 1rem;
position: relative;
}
.commentCreate {
.comment-create {
font-size: var(--font-small);
position: relative;
@ -135,12 +135,12 @@ $thumbnailWidthSmall: 1rem;
}
}
.commentCreate--reply {
.comment-create--reply {
margin-top: var(--spacing-m);
position: relative;
}
.commentCreate--nestedReply {
.comment-create--nestedReply {
margin-top: var(--spacing-s);
margin-left: calc((#{$thumbnailWidthSmall} + var(--spacing-xs)) * 2 + var(--spacing-m) + 4px);
@ -149,27 +149,40 @@ $thumbnailWidthSmall: 1rem;
}
}
.commentCreate--bottom {
.comment-create--bottom {
padding-bottom: 0;
}
.comment-create__header {
display: flex;
justify-content: space-between;
align-items: flex-end;
.comment-create__header-button {
display: flex;
justify-content: space-between;
}
.button--alt {
padding: var(--spacing-xs);
height: unset;
margin-bottom: var(--spacing-xxs);
background: unset;
}
}
.comment-create__label-wrapper {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: baseline;
flex-wrap: wrap;
width: 100%;
max-width: 50%;
.comment-create__label {
white-space: nowrap;
margin-right: var(--spacing-xs);
}
fieldset-section {
max-width: 10rem;
}
@media (max-width: $breakpoint-small) {
fieldset-section {
font-size: var(--font-xxsmall);
@ -179,14 +192,14 @@ $thumbnailWidthSmall: 1rem;
font-size: var(--font-xxsmall);
}
select {
height: 1rem;
margin: var(--spacing-xxs) 0px;
}
//select {
// height: 1rem;
// margin: var(--spacing-xxs) 0px;
//}
}
}
.commentCreate__supportCommentPreview {
.comment-create__supportCommentPreview {
display: flex;
align-items: center;
border: 1px solid var(--color-border);
@ -194,7 +207,7 @@ $thumbnailWidthSmall: 1rem;
padding: var(--spacing-s);
margin: var(--spacing-s) 0;
.commentCreate__supportCommentPreviewAmount {
.comment-create__supportCommentPreviewAmount {
margin-right: var(--spacing-m);
font-size: var(--font-large);
}
@ -223,8 +236,8 @@ $thumbnailWidthSmall: 1rem;
}
}
.commentCreate__stickerPreview {
@extend .commentCreate;
.comment-create__stickerPreview {
@extend .comment-create;
display: flex;
background-color: var(--color-header-background);
border-radius: var(--border-radius);
@ -234,12 +247,12 @@ $thumbnailWidthSmall: 1rem;
width: 100%;
height: 10rem;
.commentCreate__stickerPreviewInfo {
.comment-create__stickerPreviewInfo {
display: flex;
align-items: flex-start;
}
.commentCreate__stickerPreviewImage {
.comment-create__stickerPreviewImage {
width: 100%;
height: 100%;
margin-left: var(--spacing-m);

View file

@ -29,7 +29,12 @@ select,
background-color: var(--color-secondary);
}
}
textarea {
height: var(--height-input);
border-radius: var(--border-radius);
color: var(--color-input);
background-color: var(--color-input-bg);
}
@media (min-width: $breakpoint-small) {
textarea {
height: var(--height-input);
@ -532,6 +537,7 @@ fieldset-group {
}
.form-field__quick-action {
text-align: right;
font-size: var(--font-xsmall);
}

View file

@ -32,13 +32,17 @@ $contentMaxWidth: 60rem;
}
}
.commentCreate {
.comment-create {
border-top: 1px solid var(--color-border);
padding-top: var(--spacing-s);
.commentCreate__label {
.comment-create__label {
color: var(--color-text);
}
.comment-create__header {
display: grid;
grid-template-columns: 3fr 1fr;
}
textarea,
select,
.button:not(.button--file-action) {
@ -81,7 +85,7 @@ $contentMaxWidth: 60rem;
}
}
.commentCreate,
.comment-create,
.comment__content {
margin: var(--spacing-m);
margin-bottom: 0;

View file

@ -85,7 +85,7 @@
border-radius: 0 !important;
}
.card__main-actions .commentCreate .MuiOutlinedInput-notchedOutline {
.card__main-actions .comment-create .MuiOutlinedInput-notchedOutline {
border: 1px solid var(--color-border) !important;
border-radius: var(--border-radius) !important;
}
@ -104,7 +104,7 @@
textarea {
border: none;
margin: 9px 0px;
padding: var(--spacing-xxs) var(--spacing-xxs);
}
button {
@ -320,7 +320,7 @@
}
@media (max-width: $breakpoint-small) {
.commentCreate {
.comment-create {
.section__actions {
.button {
background-color: var(--color-header-button);