Add RTL Support (#1135)
This commit is contained in:
parent
32c7b083c8
commit
b2242f7fe4
@ -74,6 +74,7 @@
|
||||
align-self: center;
|
||||
min-width: 0;
|
||||
flex-grow: 1;
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
.content-row {
|
||||
|
||||
@ -237,7 +237,7 @@ const Audio: FC<OwnProps & StateProps> = ({
|
||||
<>
|
||||
<div className={contentClassName}>
|
||||
<div className="content-row">
|
||||
<p className="title">{renderText(getFirstLine())}</p>
|
||||
<p className="title" dir="auto">{renderText(getFirstLine())}</p>
|
||||
|
||||
<div className="message-date">
|
||||
{date && (
|
||||
@ -253,7 +253,7 @@ const Audio: FC<OwnProps & StateProps> = ({
|
||||
|
||||
{showSeekline && renderSeekline(playProgress, bufferedProgress, seekHandlers)}
|
||||
{!showSeekline && (
|
||||
<p className="duration">
|
||||
<p className="duration" dir="auto">
|
||||
{playProgress > 0 ? `${formatMediaDuration(duration * playProgress)} / ` : undefined}
|
||||
{getSecondLine()}
|
||||
</p>
|
||||
@ -318,10 +318,10 @@ function renderAudio(
|
||||
|
||||
return (
|
||||
<div className="content">
|
||||
<p className="title">{renderText(title || fileName)}</p>
|
||||
<p className="title" dir="auto">{renderText(title || fileName)}</p>
|
||||
{showSeekline && renderSeekline(playProgress, bufferedProgress, seekHandlers)}
|
||||
{!showSeekline && (
|
||||
<div className="meta">
|
||||
<div className="meta" dir="auto">
|
||||
<span className="performer">{renderText(performer || 'Unknown')}</span>
|
||||
{date && (
|
||||
<>
|
||||
@ -333,7 +333,7 @@ function renderAudio(
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<p className="duration">
|
||||
<p className="duration" dir="auto">
|
||||
{playProgress > 0 ? `${formatMediaDuration(duration * playProgress)} / ` : undefined}
|
||||
{formatMediaDuration(duration)}
|
||||
</p>
|
||||
@ -345,7 +345,7 @@ function renderVoice(voice: ApiVoice, renderedWaveform: any, isMediaUnread?: boo
|
||||
return (
|
||||
<div className="content">
|
||||
{renderedWaveform}
|
||||
<p className="voice-duration">
|
||||
<p className="voice-duration" dir="auto">
|
||||
{formatMediaDuration(voice.duration)}
|
||||
{isMediaUnread && <span>•</span>}
|
||||
</p>
|
||||
|
||||
@ -63,8 +63,8 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
||||
>
|
||||
{mediaThumbnail && renderPictogram(pictogramId, mediaThumbnail, mediaBlobUrl, isRoundVideo)}
|
||||
<div className="message-text">
|
||||
<div className="message-title">{renderText(senderTitle || title || NBSP)}</div>
|
||||
<p>
|
||||
<div className="message-title" dir="auto">{renderText(senderTitle || title || NBSP)}</div>
|
||||
<p dir="auto">
|
||||
{!message ? (
|
||||
customText || NBSP
|
||||
) : isActionMessage(message) ? (
|
||||
|
||||
@ -113,7 +113,7 @@ const File: FC<OwnProps> = ({
|
||||
) : (
|
||||
<div className={`file-icon ${color}`}>
|
||||
{extension.length <= 4 && (
|
||||
<span className="file-ext">{extension}</span>
|
||||
<span className="file-ext" dir="auto">{extension}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@ -129,8 +129,8 @@ const File: FC<OwnProps> = ({
|
||||
{onClick && <i className={buildClassName('icon-download', shouldSpinnerRender && 'hidden')} />}
|
||||
</div>
|
||||
<div className="file-info">
|
||||
<div className="file-title">{renderText(name)}</div>
|
||||
<div className="file-subtitle">
|
||||
<div className="file-title" dir="auto">{renderText(name)}</div>
|
||||
<div className="file-subtitle" dir="auto">
|
||||
<span>
|
||||
{isTransferring && transferProgress ? `${Math.round(transferProgress * 100)}%` : sizeString}
|
||||
</span>
|
||||
|
||||
@ -84,7 +84,7 @@ const GroupChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
function renderStatusOrTyping() {
|
||||
if (withUpdatingStatus && !areMessagesLoaded && !isRestricted) {
|
||||
return (
|
||||
<span className="status">{lang('Updating')}</span>
|
||||
<span className="status" dir="auto">{lang('Updating')}</span>
|
||||
);
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ const GroupChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
|
||||
if (withChatType) {
|
||||
return (
|
||||
<div className="status">{lang(getChatTypeString(chat))}</div>
|
||||
<div className="status" dir="auto">{lang(getChatTypeString(chat))}</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ const GroupChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
/>
|
||||
<div className="info">
|
||||
<div className="title">
|
||||
<h3>{renderText(getChatTitle(lang, chat))}</h3>
|
||||
<h3 dir="auto">{renderText(getChatTitle(lang, chat))}</h3>
|
||||
{chat.isVerified && <VerifiedIcon />}
|
||||
</div>
|
||||
{renderStatusOrTyping()}
|
||||
|
||||
@ -85,7 +85,7 @@ const PickerSelectedItem: FC<OwnProps & StateProps> = ({
|
||||
>
|
||||
{iconElement}
|
||||
{!isMinimized && (
|
||||
<div className="item-name">
|
||||
<div className="item-name" dir="auto">
|
||||
{titleText}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -83,13 +83,13 @@ const PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
function renderStatusOrTyping() {
|
||||
if (status) {
|
||||
return (
|
||||
<span className="status">{status}</span>
|
||||
<span className="status" dir="auto">{status}</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (withUpdatingStatus && !areMessagesLoaded) {
|
||||
return (
|
||||
<span className="status">{lang('Updating')}</span>
|
||||
<span className="status" dir="auto">{lang('Updating')}</span>
|
||||
);
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ const PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
return (
|
||||
<div className={`status ${isUserOnline(user) ? 'online' : ''}`}>
|
||||
{withUsername && user.username && <span className="handle">{user.username}</span>}
|
||||
<span className="user-status">{getUserStatus(lang, user)}</span>
|
||||
<span className="user-status" dir="auto">{getUserStatus(lang, user)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -125,7 +125,7 @@ const PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className="title">
|
||||
<h3>{fullName && renderText(fullName)}</h3>
|
||||
<h3 dir="auto">{fullName && renderText(fullName)}</h3>
|
||||
{user && user.isVerified && <VerifiedIcon />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -23,7 +23,7 @@ const TypingStatus: FC<OwnProps & StateProps> = ({ typingStatus, typingUser }) =
|
||||
return (
|
||||
<p className="typing-status">
|
||||
{typingUserName && (
|
||||
<span className="sender-name">{renderText(typingUserName)}</span>
|
||||
<span className="sender-name" dir="auto">{renderText(typingUserName)}</span>
|
||||
)}
|
||||
{typingStatus.action}
|
||||
<span className="ellipsis" />
|
||||
|
||||
@ -229,6 +229,7 @@ function processEntity(
|
||||
<a
|
||||
onClick={handleBotCommandClick}
|
||||
className="text-entity-link"
|
||||
dir="auto"
|
||||
>
|
||||
{renderMessagePart(renderedContent)}
|
||||
</a>
|
||||
@ -238,6 +239,7 @@ function processEntity(
|
||||
<a
|
||||
onClick={handleHashtagClick}
|
||||
className="text-entity-link"
|
||||
dir="auto"
|
||||
>
|
||||
{renderMessagePart(renderedContent)}
|
||||
</a>
|
||||
@ -247,6 +249,7 @@ function processEntity(
|
||||
<a
|
||||
onClick={handleHashtagClick}
|
||||
className="text-entity-link"
|
||||
dir="auto"
|
||||
>
|
||||
{renderMessagePart(renderedContent)}
|
||||
</a>
|
||||
@ -260,6 +263,7 @@ function processEntity(
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-entity-link"
|
||||
dir="auto"
|
||||
>
|
||||
{renderMessagePart(renderedContent)}
|
||||
</a>
|
||||
@ -385,6 +389,7 @@ function processEntityAsHtml(
|
||||
data-entity-type="${ApiMessageEntityTypes.MentionName}"
|
||||
data-user-id="${entity.userId}"
|
||||
contenteditable="false"
|
||||
dir="auto"
|
||||
>${renderedContent}</a>`;
|
||||
case ApiMessageEntityTypes.Url:
|
||||
case ApiMessageEntityTypes.TextUrl:
|
||||
@ -392,6 +397,7 @@ function processEntityAsHtml(
|
||||
class="text-entity-link"
|
||||
href=${getLinkUrl(rawEntityText, entity)}
|
||||
data-entity-type="${entity.type}"
|
||||
dir="auto"
|
||||
>${renderedContent}</a>`;
|
||||
default:
|
||||
return renderedContent;
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
padding-right: 0.25rem;
|
||||
flex-grow: 1;
|
||||
color: var(--color-text-secondary);
|
||||
unicode-bidi: plaintext;
|
||||
|
||||
.sender-name {
|
||||
color: var(--color-text);
|
||||
|
||||
@ -193,7 +193,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
|
||||
if (draft && draft.text.length) {
|
||||
return (
|
||||
<p className="last-message">
|
||||
<p className="last-message" dir="auto">
|
||||
<span className="draft">{lang('Draft')}</span>
|
||||
{renderText(draft.text)}
|
||||
</p>
|
||||
@ -210,7 +210,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
: lastMessageSender;
|
||||
|
||||
return (
|
||||
<p className="last-message">
|
||||
<p className="last-message" dir="auto">
|
||||
{renderText(renderActionMessageText(
|
||||
lang,
|
||||
lastMessage,
|
||||
@ -227,7 +227,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
const senderName = getMessageSenderName(lang, chatId, lastMessageSender);
|
||||
|
||||
return (
|
||||
<p className="last-message">
|
||||
<p className="last-message" dir="auto">
|
||||
{senderName && (
|
||||
<span className="sender-name">{renderText(senderName)}</span>
|
||||
)}
|
||||
|
||||
@ -82,7 +82,7 @@ const ContactList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
</ListItem>
|
||||
))
|
||||
) : viewportIds && !viewportIds.length ? (
|
||||
<p className="no-results" key="no-results">
|
||||
<p className="no-results" key="no-results" dir="auto">
|
||||
{filter.length ? 'No contacts matched your search.' : 'Contact list is empty.'}
|
||||
</p>
|
||||
) : (
|
||||
|
||||
@ -86,7 +86,7 @@ const ChatMessage: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="info">
|
||||
<div className="info-row">
|
||||
<div className="title">
|
||||
<h3>{renderText(getChatTitle(lang, chat, privateChatUser))}</h3>
|
||||
<h3 dir="auto">{renderText(getChatTitle(lang, chat, privateChatUser))}</h3>
|
||||
{chat.isVerified && <VerifiedIcon />}
|
||||
</div>
|
||||
<div className="message-date">
|
||||
@ -97,7 +97,7 @@ const ChatMessage: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
|
||||
</div>
|
||||
<div className="subtitle">
|
||||
<div className="message">
|
||||
<div className="message" dir="auto">
|
||||
{renderMessageSummary(lang, message, mediaBlobUrl || mediaThumbnail, searchQuery, isRoundVideo)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -95,15 +95,24 @@
|
||||
.ListItem.search-result {
|
||||
.ChatInfo {
|
||||
.handle {
|
||||
unicode-bidi: plaintext;
|
||||
color: var(--color-primary);
|
||||
|
||||
&::before {
|
||||
content: '@';
|
||||
html[lang=ar] & {
|
||||
content: ' ،@';
|
||||
margin-inline-end: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: ', ';
|
||||
color: var(--color-text-secondary);
|
||||
|
||||
html[lang=ar] & {
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('BlockedUsers')}</span>
|
||||
{blockedCount > 0 && (
|
||||
<span className="subtitle">
|
||||
<span className="subtitle" dir="auto">
|
||||
{lang('Users', blockedCount)}
|
||||
</span>
|
||||
)}
|
||||
@ -89,7 +89,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('TwoStepVerification')}</span>
|
||||
<span className="subtitle">{lang(hasPassword ? 'PasswordOn' : 'PasswordOff')}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{lang(hasPassword ? 'PasswordOn' : 'PasswordOff')}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -100,7 +102,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('SessionsTitle')}</span>
|
||||
{sessionsCount > 0 && (
|
||||
<span className="subtitle">
|
||||
<span className="subtitle" dir="auto">
|
||||
{sessionsCount === 1 ? '1 session' : `${sessionsCount} sessions`}
|
||||
</span>
|
||||
)}
|
||||
@ -117,7 +119,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('PrivacyPhoneTitle')}</span>
|
||||
<span className="subtitle">{getVisibilityValue(visibilityPrivacyPhoneNumber)}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{getVisibilityValue(visibilityPrivacyPhoneNumber)}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -126,7 +130,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('LastSeenTitle')}</span>
|
||||
<span className="subtitle">{getVisibilityValue(visibilityPrivacyLastSeen)}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{getVisibilityValue(visibilityPrivacyLastSeen)}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -135,7 +141,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('PrivacyProfilePhotoTitle')}</span>
|
||||
<span className="subtitle">{getVisibilityValue(visibilityPrivacyProfilePhoto)}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{getVisibilityValue(visibilityPrivacyProfilePhoto)}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -144,7 +152,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('PrivacyForwardsTitle')}</span>
|
||||
<span className="subtitle">{getVisibilityValue(visibilityPrivacyForwarding)}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{getVisibilityValue(visibilityPrivacyForwarding)}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -153,7 +163,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
<div className="multiline-menu-item">
|
||||
<span className="title">{lang('WhoCanAddMe')}</span>
|
||||
<span className="subtitle">{getVisibilityValue(visibilityPrivacyGroupChats)}</span>
|
||||
<span className="subtitle" dir="auto">
|
||||
{getVisibilityValue(visibilityPrivacyGroupChats)}
|
||||
</span>
|
||||
</div>
|
||||
</ListItem>
|
||||
</div>
|
||||
|
||||
@ -67,13 +67,13 @@ const SettingsPrivacyBlockedUsers: FC<StateProps & DispatchProps> = ({
|
||||
style={`top: ${(viewportOffset + i) * CHAT_HEIGHT_PX}px;`}
|
||||
>
|
||||
<Avatar size="medium" user={user} chat={chat} />
|
||||
<div className="contact-info">
|
||||
<h3>{renderText((isPrivate ? getUserFullName(user) : getChatTitle(lang, chat!)) || '')}</h3>
|
||||
<div className="contact-info" dir="auto">
|
||||
<h3 dir="auto">{renderText((isPrivate ? getUserFullName(user) : getChatTitle(lang, chat!)) || '')}</h3>
|
||||
{user && user.phoneNumber && (
|
||||
<div className="contact-phone">{formatPhoneNumberWithCode(user.phoneNumber)}</div>
|
||||
<div className="contact-phone" dir="auto">{formatPhoneNumberWithCode(user.phoneNumber)}</div>
|
||||
)}
|
||||
{user && !user.phoneNumber && user.username && (
|
||||
<div className="contact-username">@{user.username}</div>
|
||||
<div className="contact-username" dir="auto">@{user.username}</div>
|
||||
)}
|
||||
</div>
|
||||
</ListItem>
|
||||
|
||||
@ -121,7 +121,7 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
|
||||
ripple
|
||||
>
|
||||
<i className={`icon-${type.icon}`} />
|
||||
<h3 className="chat-type">{lang(type.title)}</h3>
|
||||
<h3 className="chat-type" dir="auto">{lang(type.title)}</h3>
|
||||
<Checkbox
|
||||
label=""
|
||||
checked={selectedChatTypes.includes(type.key)}
|
||||
@ -179,7 +179,9 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
|
||||
placeholder={lang('Search')}
|
||||
/>
|
||||
) : (
|
||||
<p className="max-items-reached">{`Sorry, you can't add more than ${MAX_CHATS} chats.`}</p>
|
||||
<p className="max-items-reached" dir="auto">
|
||||
{`Sorry, you can't add more than ${MAX_CHATS} chats.`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<InfiniteScroll
|
||||
|
||||
@ -139,7 +139,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="settings-item-description mb-3">
|
||||
<p className="settings-item-description mb-3" dir="auto">
|
||||
{lang('CreateNewFilterInfo')}
|
||||
</p>
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ const SettingsTwoFaCongratulations: FC<OwnProps & StateProps> = ({
|
||||
<div className="settings-content-header">
|
||||
<AnimatedEmoji sticker={animatedEmoji} />
|
||||
|
||||
<p className="settings-item-description mb-3">
|
||||
<p className="settings-item-description mb-3" dir="auto">
|
||||
{lang('TwoStepVerificationPasswordSetInfo')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -29,7 +29,7 @@ const SettingsTwoFaEnabled: FC<OwnProps & StateProps> = ({
|
||||
<div className="settings-content-header">
|
||||
<AnimatedEmoji sticker={animatedEmoji} />
|
||||
|
||||
<p className="settings-item-description mb-3">
|
||||
<p className="settings-item-description mb-3" dir="auto">
|
||||
{renderText(lang('EnabledPasswordText'), ['br'])}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -25,7 +25,7 @@ const SettingsTwoFaStart: FC<OwnProps & StateProps> = ({ animatedEmoji, onStart
|
||||
<div className="settings-content-header">
|
||||
<AnimatedEmoji sticker={animatedEmoji} />
|
||||
|
||||
<p className="settings-item-description mb-3">
|
||||
<p className="settings-item-description mb-3" dir="auto">
|
||||
{lang('SetAdditionalPasswordInfo')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
padding: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.75rem;
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ const MediaViewerFooter: FC<OwnProps> = ({ text = '', isHideable, onClick }) =>
|
||||
<div className={`MediaViewerFooter ${isHideable ? 'hideable' : ''}`} onClick={stopEvent}>
|
||||
{text && (
|
||||
<div className="media-viewer-footer-content" onClick={onClick}>
|
||||
<p className={`media-text custom-scroll ${isMultiline ? 'multiline' : ''}`}>{text}</p>
|
||||
<p className={`media-text custom-scroll ${isMultiline ? 'multiline' : ''}`} dir="auto">{text}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -58,10 +58,10 @@ const SenderInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<Avatar key={sender.id} size="medium" user={sender as ApiUser} />
|
||||
)}
|
||||
<div className="meta">
|
||||
<div className="title">
|
||||
<div className="title" dir="auto">
|
||||
{senderTitle && renderText(senderTitle)}
|
||||
</div>
|
||||
<div className="date">
|
||||
<div className="date" dir="auto">
|
||||
{isAvatar ? lang('lng_mediaview_profile_photo') : formatMediaDateTime(lang, message!.date * 1000)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -102,9 +102,9 @@ function renderAudio(audio: ApiAudio) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="title">{renderText(title || fileName)}</div>
|
||||
<div className="title" dir="auto">{renderText(title || fileName)}</div>
|
||||
{performer && (
|
||||
<div className="subtitle">{renderText(performer)}</div>
|
||||
<div className="subtitle" dir="auto">{renderText(performer)}</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@ -113,8 +113,8 @@ function renderAudio(audio: ApiAudio) {
|
||||
function renderVoice(subtitle: string, senderName?: string) {
|
||||
return (
|
||||
<>
|
||||
<div className="title">{senderName && renderText(senderName)}</div>
|
||||
<div className="subtitle">{subtitle}</div>
|
||||
<div className="title" dir="auto">{senderName && renderText(senderName)}</div>
|
||||
<div className="subtitle" dir="auto">{subtitle}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -86,10 +86,10 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
|
||||
/>
|
||||
{mediaThumbnail && renderPictogram(mediaThumbnail, mediaBlobUrl)}
|
||||
<div className="message-text">
|
||||
<div className="title">
|
||||
<div className="title" dir="auto">
|
||||
{customTitle || `${lang('PinnedMessage')} ${index > 0 ? `#${count - index}` : ''}`}
|
||||
</div>
|
||||
<p>{renderText(text)}</p>
|
||||
<p dir="auto">{renderText(text)}</p>
|
||||
</div>
|
||||
|
||||
<RippleEffect />
|
||||
|
||||
@ -702,7 +702,7 @@ function renderMessages(
|
||||
teactFastList
|
||||
>
|
||||
<div className="sticky-date" key="date-header">
|
||||
<span>
|
||||
<span dir="auto">
|
||||
{isSchedule && dateGroup.originalDate === SCHEDULED_WHEN_ONLINE && (
|
||||
lang('MessageScheduledUntilOnline')
|
||||
)}
|
||||
|
||||
@ -226,6 +226,7 @@
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
unicode-bidi: plaintext;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
display: block;
|
||||
@ -264,6 +265,10 @@
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
.user-status, .status {
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
}
|
||||
|
||||
.Avatar {
|
||||
|
||||
@ -256,6 +256,8 @@
|
||||
overflow: hidden;
|
||||
line-height: 1.375rem;
|
||||
font-family: Roboto, -apple-system, "Apple Color Emoji", "Helvetica Neue", sans-serif;
|
||||
unicode-bidi: plaintext;
|
||||
text-align: initial;
|
||||
|
||||
&.overflown {
|
||||
overflow-y: auto;
|
||||
@ -278,6 +280,8 @@
|
||||
bottom: .9375rem;
|
||||
color: var(--color-placeholders);
|
||||
pointer-events: none;
|
||||
unicode-bidi: plaintext;
|
||||
text-align: initial;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
bottom: 0.6875rem;
|
||||
@ -301,6 +305,8 @@
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: -10;
|
||||
unicode-bidi: plaintext;
|
||||
text-align: initial;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,9 @@ const EmojiCategory: FC<OwnProps> = ({
|
||||
id={`emoji-category-${index}`}
|
||||
className="symbol-set"
|
||||
>
|
||||
<p className="symbol-set-name">{lang(category.id === 'recent' ? 'RecentStickers' : `Emoji${index}`)}</p>
|
||||
<p className="symbol-set-name" dir="auto">
|
||||
{lang(category.id === 'recent' ? 'RecentStickers' : `Emoji${index}`)}
|
||||
</p>
|
||||
<div
|
||||
className={buildClassName('symbol-set-container', transitionClassNames)}
|
||||
// @ts-ignore
|
||||
|
||||
@ -356,6 +356,7 @@ const MessageInput: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
ref={inputRef}
|
||||
id={editableInputId || EDITABLE_INPUT_ID}
|
||||
className={className}
|
||||
dir="auto"
|
||||
contentEditable
|
||||
onClick={focusInput}
|
||||
onChange={handleChange}
|
||||
@ -364,8 +365,8 @@ const MessageInput: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
onContextMenu={stopEvent}
|
||||
onTouchCancel={handleTouchSelection}
|
||||
/>
|
||||
<div ref={cloneRef} className={buildClassName(className, 'clone')} />
|
||||
<span className="placeholder-text">{placeholder}</span>
|
||||
<div ref={cloneRef} className={buildClassName(className, 'clone')} dir="auto" />
|
||||
<span className="placeholder-text" dir="auto">{placeholder}</span>
|
||||
<TextFormatter
|
||||
isOpen={isTextFormatterOpen}
|
||||
anchorPosition={textFormatterAnchorPosition}
|
||||
|
||||
@ -44,6 +44,10 @@
|
||||
.option-wrapper {
|
||||
position: relative;
|
||||
|
||||
.form-control {
|
||||
padding-right: 3rem;
|
||||
}
|
||||
|
||||
.option-remove-button {
|
||||
position: absolute;
|
||||
top: 0.3125rem;
|
||||
|
||||
@ -337,6 +337,7 @@ const PollModal: FC<OwnProps> = ({ isOpen, onSend, onClear }) => {
|
||||
ref={solutionRef}
|
||||
className="form-control"
|
||||
contentEditable
|
||||
dir="auto"
|
||||
onChange={(e) => setSolution(e.currentTarget.innerHTML)}
|
||||
/>
|
||||
<div className="note">{lang('CreatePoll.ExplanationInfo')}</div>
|
||||
|
||||
@ -122,6 +122,12 @@
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: initial;
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
&-container {
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
&-button {
|
||||
|
||||
@ -258,7 +258,7 @@ const TextFormatter: FC<OwnProps> = ({
|
||||
}
|
||||
|
||||
const text = getSelectedText();
|
||||
document.execCommand('insertHTML', false, `<code class="text-entity-code">${text}</code>`);
|
||||
document.execCommand('insertHTML', false, `<code class="text-entity-code" dir="auto">${text}</code>`);
|
||||
onClose();
|
||||
}, [
|
||||
getSelectedElement, getSelectedText, onClose,
|
||||
@ -282,7 +282,11 @@ const TextFormatter: FC<OwnProps> = ({
|
||||
|
||||
const text = getSelectedText();
|
||||
restoreSelection();
|
||||
document.execCommand('insertHTML', false, `<a href=${formattedLinkUrl} class="text-entity-link">${text}</a>`);
|
||||
document.execCommand(
|
||||
'insertHTML',
|
||||
false,
|
||||
`<a href=${formattedLinkUrl} class="text-entity-link" dir="auto">${text}</a>`,
|
||||
);
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -424,6 +428,7 @@ const TextFormatter: FC<OwnProps> = ({
|
||||
placeholder="Enter URL..."
|
||||
autoComplete="off"
|
||||
inputMode="url"
|
||||
dir="auto"
|
||||
onChange={handleLinkUrlChange}
|
||||
onScroll={updateInputStyles}
|
||||
/>
|
||||
|
||||
@ -73,6 +73,7 @@ export default function useMentionTooltip(
|
||||
data-entity-type="${ApiMessageEntityTypes.MentionName}"
|
||||
data-user-id="${user.id}"
|
||||
contenteditable="false"
|
||||
dir="auto"
|
||||
>${getUserFirstOrLastName(user)}</a>`;
|
||||
|
||||
const atIndex = html.lastIndexOf('@');
|
||||
|
||||
@ -78,7 +78,7 @@ const CommentButton: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<i className="icon-comments-sticker" />
|
||||
{(!recentRepliers || recentRepliers.length === 0) && <i className="icon-comments" />}
|
||||
{renderRecentRepliers()}
|
||||
<div className="label">
|
||||
<div className="label" dir="auto">
|
||||
{messagesCount ? lang('Comments', messagesCount, 'i') : lang('LeaveAComment')}
|
||||
</div>
|
||||
<i className="icon-next" />
|
||||
|
||||
@ -35,7 +35,7 @@ const MentionLink: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<a onClick={handleClick} className="text-entity-link">
|
||||
<a onClick={handleClick} className="text-entity-link" dir="auto">
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
@ -503,9 +503,10 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
noMediaCorners && 'no-media-corners',
|
||||
);
|
||||
const hasCustomAppendix = isLastInGroup && !textParts && !asForwarded && !hasThread;
|
||||
const shouldInlineMeta = !webPage && !animatedEmoji && textParts;
|
||||
|
||||
return (
|
||||
<div className={className} onDoubleClick={handleContentDoubleClick}>
|
||||
<div className={className} onDoubleClick={handleContentDoubleClick} dir="auto">
|
||||
{renderSenderName()}
|
||||
{hasReply && (
|
||||
<EmbeddedMessage
|
||||
@ -605,7 +606,19 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
{poll && (
|
||||
<Poll message={message} poll={poll} onSendVote={handleVoteSend} />
|
||||
)}
|
||||
{!animatedEmoji && textParts && <p className="text-content">{textParts}</p>}
|
||||
{!animatedEmoji && textParts && (
|
||||
<p className={`text-content ${shouldInlineMeta ? 'with-meta' : ''}`} dir="auto">
|
||||
{textParts}
|
||||
{shouldInlineMeta && (
|
||||
<MessageMeta
|
||||
message={message}
|
||||
outgoingStatus={outgoingStatus}
|
||||
signature={signature}
|
||||
onClick={handleMessageSelect}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{webPage && (
|
||||
<WebPage
|
||||
message={message}
|
||||
@ -737,13 +750,14 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
className={contentClassName}
|
||||
// @ts-ignore
|
||||
style={style}
|
||||
dir="auto"
|
||||
>
|
||||
{withAppendix && (<div className="svg-appendix" ref={appendixRef} />)}
|
||||
{asForwarded && !customShape && (!isInDocumentGroup || isFirstInDocumentGroup) && (
|
||||
<div className="message-title">{lang('ForwardedMessage')}</div>
|
||||
)}
|
||||
{renderContent()}
|
||||
{(!isInDocumentGroup || isLastInDocumentGroup) && (
|
||||
{(!isInDocumentGroup || isLastInDocumentGroup) && !(!webPage && !animatedEmoji && textParts) && (
|
||||
<MessageMeta
|
||||
message={message}
|
||||
outgoingStatus={outgoingStatus}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(#999999, 0.6);
|
||||
border-radius: .65rem;
|
||||
border-radius: .625rem;
|
||||
padding: 0 .25rem;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
@ -64,9 +64,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
.media:not(.text):dir(rtl) &,
|
||||
.Message .custom-shape:dir(rtl) & {
|
||||
right: auto !important;
|
||||
left: .25rem;
|
||||
padding: 0 .375rem 0 .3125rem;
|
||||
}
|
||||
|
||||
.is-forwarded.media:not(.text):dir(rtl) &,
|
||||
.Message .is-forwarded.custom-shape:dir(rtl) & {
|
||||
left: .8125rem;
|
||||
}
|
||||
|
||||
.is-forwarded.media:not(.text) & {
|
||||
bottom: 0.9rem;
|
||||
right: 0.8rem;
|
||||
bottom: 0.935rem;
|
||||
right: 0.8125rem;
|
||||
}
|
||||
|
||||
.emoji-only & {
|
||||
@ -80,6 +92,8 @@
|
||||
.MessageOutgoingStatus {
|
||||
margin-left: -.1875rem;
|
||||
font-size: 1.1875rem;
|
||||
border-radius: .625rem;
|
||||
|
||||
.Message.own & {
|
||||
color: var(--color-accent-own);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
.Poll {
|
||||
min-width: 15rem;
|
||||
text-align: initial;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
min-width: 50vw;
|
||||
|
||||
@ -256,7 +256,7 @@ const Poll: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="Poll">
|
||||
<div className="Poll" dir="auto">
|
||||
{renderSolution()}
|
||||
<div className="poll-question">{renderText(summary.question)}</div>
|
||||
<div className="poll-type">
|
||||
|
||||
@ -72,6 +72,7 @@ const WebPage: FC<OwnProps> = ({
|
||||
<div
|
||||
className={className}
|
||||
data-initial={(siteName || displayUrl)[0]}
|
||||
dir="auto"
|
||||
>
|
||||
{photo && (
|
||||
<Photo
|
||||
|
||||
@ -10,6 +10,34 @@
|
||||
margin: 0;
|
||||
word-break: break-word;
|
||||
line-height: 1.3125;
|
||||
text-align: initial;
|
||||
display: flow-root;
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.text-entity-link {
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.text-content,
|
||||
&.document {
|
||||
& > .MessageMeta {
|
||||
position: relative;
|
||||
top: .4375rem;
|
||||
bottom: auto !important;
|
||||
float: right;
|
||||
line-height: 1;
|
||||
margin-left: .4375rem;
|
||||
margin-right: -.5rem;
|
||||
}
|
||||
|
||||
&:dir(rtl) {
|
||||
& > .MessageMeta {
|
||||
float: left;
|
||||
margin-left: -.25rem;
|
||||
margin-right: .4375rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark .Message.own & {
|
||||
@ -24,6 +52,10 @@
|
||||
|
||||
&:not(.custom-shape) {
|
||||
font-size: var(--message-text-size, 1rem);
|
||||
|
||||
& > .content-inner {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.matching-text-highlight {
|
||||
@ -40,6 +72,7 @@
|
||||
font-weight: 500;
|
||||
line-height: 1.25rem;
|
||||
color: var(--accent-color);
|
||||
unicode-bidi: plaintext;
|
||||
display: flex;
|
||||
|
||||
& > .interactive {
|
||||
@ -94,8 +127,8 @@
|
||||
|
||||
.admin-title {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
text-align: right;
|
||||
margin-inline-start: 1rem;
|
||||
text-align: end;
|
||||
font-weight: 400;
|
||||
font-size: 0.75rem;
|
||||
margin-top: -0.1rem;
|
||||
@ -118,7 +151,7 @@
|
||||
&.has-solid-background {
|
||||
padding: .3125rem .5rem .375rem;
|
||||
|
||||
.text-content:last-child::after {
|
||||
.forwarded-message > .text-content:not(.with-meta):last-child::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: var(--meta-safe-area-size);
|
||||
@ -210,7 +243,7 @@
|
||||
width: 1.25rem;
|
||||
background-size: 1.25rem;
|
||||
color: transparent;
|
||||
margin-right: 1px;
|
||||
margin-inline-end: 1px;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&::selection {
|
||||
@ -531,8 +564,9 @@
|
||||
.text-entity-link {
|
||||
color: var(--color-links) !important;
|
||||
text-decoration: none;
|
||||
word-break: none;
|
||||
word-break: break-word;
|
||||
cursor: pointer;
|
||||
unicode-bidi: initial;
|
||||
|
||||
&:hover, &:active, &:visited {
|
||||
color: var(--color-links-hover) !important;
|
||||
|
||||
@ -86,7 +86,7 @@ const ChatExtra: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="ChatExtra">
|
||||
{formattedNumber && !!formattedNumber.length && (
|
||||
<ListItem icon="phone" multiline narrow ripple onClick={() => copy(formattedNumber, lang('Phone'))}>
|
||||
<span className="title">{formattedNumber}</span>
|
||||
<span className="title" dir="auto">{formattedNumber}</span>
|
||||
<span className="subtitle">{lang('Phone')}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
@ -98,7 +98,7 @@ const ChatExtra: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
ripple
|
||||
onClick={() => copy(`@${printedUsername}`, lang('Username'))}
|
||||
>
|
||||
<span className="title">{renderText(printedUsername)}</span>
|
||||
<span className="title" dir="auto">{renderText(printedUsername)}</span>
|
||||
<span className="subtitle">{lang('Username')}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
@ -109,7 +109,9 @@ const ChatExtra: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
narrow
|
||||
isStatic
|
||||
>
|
||||
<span className="title">{renderText(description, ['br', 'links', 'emoji'])}</span>
|
||||
<span className="title" dir="auto">
|
||||
{renderText(description, ['br', 'links', 'emoji'])}
|
||||
</span>
|
||||
<span className="subtitle">{lang(userId ? 'UserBio' : 'Info')}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
|
||||
@ -80,7 +80,7 @@ const GifSearch: FC<StateProps & DispatchProps> = ({
|
||||
|
||||
if (!results.length) {
|
||||
return (
|
||||
<p className="helper-text">{lang('NoGIFsFound')}</p>
|
||||
<p className="helper-text" dir="auto">{lang('NoGIFsFound')}</p>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ const PollAnswerResults: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
{voters && renderViewMoreButton()}
|
||||
</div>
|
||||
<div className="answer-head">
|
||||
<span className="answer-title">{text}</span>
|
||||
<span className="answer-title" dir="auto">{text}</span>
|
||||
<span className="answer-percent">{getPercentage(answerVote.votersCount, totalVoters)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -35,7 +35,7 @@ const PollResults: FC<StateProps> = ({
|
||||
|
||||
return (
|
||||
<div className="PollResults">
|
||||
<h3 className="poll-question">{summary.question}</h3>
|
||||
<h3 className="poll-question" dir="auto">{summary.question}</h3>
|
||||
<div className="poll-results-list custom-scroll">
|
||||
{lastSyncTime && summary.answers.map((answer) => (
|
||||
<PollAnswerResults
|
||||
|
||||
@ -157,13 +157,13 @@ const PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
if (user) {
|
||||
return (
|
||||
<div className={`status ${isUserOnline(user) ? 'online' : ''}`}>
|
||||
<span className="user-status">{getUserStatus(lang, user)}</span>
|
||||
<span className="user-status" dir="auto">{getUserStatus(lang, user)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="status">{
|
||||
<span className="status" dir="auto">{
|
||||
isChatChannel(chat!)
|
||||
? lang('Subscribers', chat!.membersCount, 'i')
|
||||
: lang('Members', chat!.membersCount, 'i')
|
||||
@ -203,11 +203,11 @@ const PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="info">
|
||||
{isSavedMessages ? (
|
||||
<div className="title">
|
||||
<h3>{lang('SavedMessages')}</h3>
|
||||
<h3 dir="auto">{lang('SavedMessages')}</h3>
|
||||
</div>
|
||||
) : (
|
||||
<div className="title">
|
||||
<h3>{fullName && renderText(fullName)}</h3>
|
||||
<h3 dir="auto">{fullName && renderText(fullName)}</h3>
|
||||
{isVerifiedIconShown && <VerifiedIcon />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -8,5 +8,7 @@
|
||||
margin-bottom: 0.125rem;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-secondary);
|
||||
unicode-bidi: plaintext;
|
||||
text-align: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,10 +108,10 @@ const RightSearch: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<Avatar chat={senderChat} user={senderUser} />
|
||||
<div className="info">
|
||||
<div className="title">
|
||||
<h3>{title && renderText(title)}</h3>
|
||||
<h3 dir="auto">{title && renderText(title)}</h3>
|
||||
<LastMessageMeta message={message} />
|
||||
</div>
|
||||
<div className="subtitle">
|
||||
<div className="subtitle" dir="auto">
|
||||
{renderText(text, ['emoji', 'highlight'], { highlight: query })}
|
||||
</div>
|
||||
</div>
|
||||
@ -127,13 +127,15 @@ const RightSearch: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
onLoadMore={searchTextMessagesLocal}
|
||||
noFastList
|
||||
>
|
||||
<p className="helper-text">
|
||||
<p className="helper-text" dir="auto">
|
||||
{!query ? (
|
||||
'Search messages'
|
||||
lang('lng_dlg_search_for_messages')
|
||||
) : (totalCount === 0 || !foundResults.length) ? (
|
||||
lang('lng_search_no_results')
|
||||
) : totalCount === 1 ? (
|
||||
'1 message found'
|
||||
) : (
|
||||
`${(foundResults.length && (totalCount || foundResults.length)) || 'No'} messages found`
|
||||
`${(foundResults.length && (totalCount || foundResults.length))} messages found`
|
||||
)}
|
||||
</p>
|
||||
{foundResults.map(renderSearchResult)}
|
||||
|
||||
@ -80,8 +80,8 @@ const StickerSetResult: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div key={set.id} className="sticker-set">
|
||||
<div className="sticker-set-header">
|
||||
<div className="title-wrapper">
|
||||
<h3 className="title">{set.title}</h3>
|
||||
<p className="count">{lang('Stickers', set.count, 'i')}</p>
|
||||
<h3 className="title" dir="auto">{set.title}</h3>
|
||||
<p className="count" dir="auto">{lang('Stickers', set.count, 'i')}</p>
|
||||
</div>
|
||||
<Button
|
||||
className={isAdded ? 'is-added' : undefined}
|
||||
|
||||
@ -200,8 +200,8 @@ const ManageChannel: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
</div>
|
||||
<div className="section">
|
||||
<ListItem icon="group" multiline ripple onClick={handleClickSubscribers}>
|
||||
<span className="title">{lang('ChannelSubscribers')}</span>
|
||||
<span className="subtitle">{lang('Subscribers', chat.membersCount!, 'i')}</span>
|
||||
<span className="title" dir="auto">{lang('ChannelSubscribers')}</span>
|
||||
<span className="subtitle" dir="auto">{lang('Subscribers', chat.membersCount!, 'i')}</span>
|
||||
</ListItem>
|
||||
</div>
|
||||
<div className="section">
|
||||
|
||||
@ -86,7 +86,7 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
||||
</div>
|
||||
|
||||
<div className="section">
|
||||
<p className="text-muted">
|
||||
<p className="text-muted" dir="auto">
|
||||
{isChannel
|
||||
? 'You can add administrators to help you manage your channel.'
|
||||
: 'You can add administrators to help you manage your group.'}
|
||||
|
||||
@ -135,7 +135,7 @@ const ManageChatPrivacyType: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
checkUsername={checkPublicLink}
|
||||
onChange={setUsername}
|
||||
/>
|
||||
<p className="section-info">
|
||||
<p className="section-info" dir="auto">
|
||||
{lang(`${langPrefix2}.Username.CreatePublicLinkHelp`)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -185,7 +185,7 @@ const ManageDiscussion: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
function renderDiscussionGroups() {
|
||||
return (
|
||||
<div>
|
||||
<p className="section-help">{lang('DiscussionChannelHelp')}</p>
|
||||
<p className="section-help" dir="auto">{lang('DiscussionChannelHelp')}</p>
|
||||
|
||||
<div teactFastList>
|
||||
<ListItem
|
||||
@ -212,7 +212,7 @@ const ManageDiscussion: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<NothingFound key="nothing-found" teactOrderKey={0} text="No discussion groups found" />
|
||||
)}
|
||||
</div>
|
||||
<p className="mt-4 mb-0 section-help">{lang('DiscussionChannelHelp2')}</p>
|
||||
<p className="mt-4 mb-0 section-help" dir="auto">{lang('DiscussionChannelHelp2')}</p>
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmLinkGroupDialogOpen}
|
||||
onClose={closeConfirmLinkGroupDialog}
|
||||
|
||||
@ -67,8 +67,8 @@ const Checkbox: FC<OwnProps> = ({
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<div className="Checkbox-main">
|
||||
<span className="label">{label}</span>
|
||||
{subLabel && <span className="subLabel">{subLabel}</span>}
|
||||
<span className="label" dir="auto">{label}</span>
|
||||
{subLabel && <span className="subLabel" dir="auto">{subLabel}</span>}
|
||||
</div>
|
||||
{isLoading && <Spinner />}
|
||||
</label>
|
||||
|
||||
@ -62,6 +62,7 @@ const InputText: FC<OwnProps> = ({
|
||||
className="form-control"
|
||||
type="text"
|
||||
id={id}
|
||||
dir="auto"
|
||||
value={value || ''}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
|
||||
@ -20,6 +20,7 @@ const Link: FC<OwnProps> = ({ children, className, onClick }) => {
|
||||
<a
|
||||
href="#"
|
||||
className={buildClassName('Link', className)}
|
||||
dir="auto"
|
||||
onClick={onClick ? handleClick : undefined}
|
||||
>
|
||||
{children}
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
color: var(--color-text);
|
||||
--ripple-color: rgba(0, 0, 0, .08);
|
||||
cursor: pointer;
|
||||
unicode-bidi: plaintext;
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: var(--color-chat-hover);
|
||||
|
||||
@ -93,6 +93,7 @@ const SearchInput: FC<OwnProps> = ({
|
||||
ref={inputRef}
|
||||
id={inputId}
|
||||
type="text"
|
||||
dir="auto"
|
||||
placeholder={placeholder || lang('Search')}
|
||||
className="form-control"
|
||||
value={value}
|
||||
|
||||
@ -22,6 +22,7 @@ type VirtualDomHead = {
|
||||
};
|
||||
|
||||
const FILTERED_ATTRIBUTES = new Set(['key', 'ref', 'teactFastList', 'teactOrderKey']);
|
||||
const HTML_ATTRIBUTES = new Set(['dir']);
|
||||
const MAPPED_ATTRIBUTES: { [k: string]: string } = {
|
||||
autoPlay: 'autoplay',
|
||||
autoComplete: 'autocomplete',
|
||||
@ -428,7 +429,7 @@ function addAttribute(element: HTMLElement, key: string, value: any) {
|
||||
element.style.cssText = value;
|
||||
} else if (key.startsWith('on')) {
|
||||
addEventListener(element, key, value);
|
||||
} else if (key.startsWith('data-')) {
|
||||
} else if (key.startsWith('data-') || HTML_ATTRIBUTES.has(key)) {
|
||||
element.setAttribute(key, value);
|
||||
} else if (!FILTERED_ATTRIBUTES.has(key)) {
|
||||
(element as any)[MAPPED_ATTRIBUTES[key] || key] = value;
|
||||
@ -444,7 +445,7 @@ function removeAttribute(element: HTMLElement, key: string, value: any) {
|
||||
element.style.cssText = '';
|
||||
} else if (key.startsWith('on')) {
|
||||
removeEventListener(element, key, value);
|
||||
} else if (key.startsWith('data-')) {
|
||||
} else if (key.startsWith('data-') || HTML_ATTRIBUTES.has(key)) {
|
||||
element.removeAttribute(key);
|
||||
} else if (!FILTERED_ATTRIBUTES.has(key)) {
|
||||
delete (element as any)[MAPPED_ATTRIBUTES[key] || key];
|
||||
|
||||
@ -120,6 +120,12 @@ addReducer('reset', () => {
|
||||
cacheApi.clear(CUSTOM_BG_CACHE_NAME);
|
||||
cacheApi.clear(LANG_CACHE_NAME);
|
||||
|
||||
const langChachePrefix = LANG_CACHE_NAME.replace(/\d+$/, '');
|
||||
const langCacheVersion = (LANG_CACHE_NAME.match(/\d+$/) || [0])[0];
|
||||
for (let i = 0; i < langCacheVersion; i++) {
|
||||
cacheApi.clear(`${langChachePrefix}${i === 0 ? '' : i}`);
|
||||
}
|
||||
|
||||
getDispatch().init();
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user