Spoilers: Various fixes
This commit is contained in:
parent
bc18224114
commit
a71a13414a
@ -305,7 +305,7 @@ function processEntity(
|
|||||||
if (isSimple) {
|
if (isSimple) {
|
||||||
const text = renderNestedMessagePart();
|
const text = renderNestedMessagePart();
|
||||||
if (entity.type === ApiMessageEntityTypes.Spoiler) {
|
if (entity.type === ApiMessageEntityTypes.Spoiler) {
|
||||||
return <Spoiler isInactive>{text}</Spoiler>;
|
return <Spoiler>{text}</Spoiler>;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +1,34 @@
|
|||||||
.Spoiler {
|
.Spoiler {
|
||||||
transition: color 250ms ease;
|
&.concealed {
|
||||||
|
|
||||||
.text-entity-link {
|
|
||||||
transition: color 250ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.is-revealed) {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: transparent;
|
|
||||||
background-image: url('../../../assets/spoiler-dots-black.png');
|
background-image: url('../../../assets/spoiler-dots-black.png');
|
||||||
background-size: auto 100%;
|
background-size: auto min(100%, 1.125rem);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
&.animate {
|
html.theme-dark &,
|
||||||
animation: pulse-opacity-light 1.75s linear infinite;
|
html.theme-light .ListItem.selected &,
|
||||||
|
.ActionMessage &,
|
||||||
|
.MediaViewerFooter & {
|
||||||
|
background-image: url('../../../assets/spoiler-dots-white.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-entity-link {
|
.emoji-only & {
|
||||||
color: transparent !important;
|
background-size: auto 1.125rem;
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html.theme-dark &:not(.is-revealed),
|
&.animated {
|
||||||
html.theme-light .ListItem.selected &:not(.is-revealed),
|
animation: pulse-opacity-light 1.75s linear infinite;
|
||||||
html.theme-light .ActionMessage &:not(.is-revealed) {
|
}
|
||||||
background-image: url('../../../assets/spoiler-dots-white.png');
|
|
||||||
|
span {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 250ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.concealed span {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { MouseEvent as ReactMouseEvent } from 'react';
|
||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useEffect,
|
FC, memo, useCallback, useEffect,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
@ -10,7 +11,6 @@ import './Spoiler.scss';
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
messageId?: number;
|
messageId?: number;
|
||||||
isInactive?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const spoilersByMessageId: Map<number, VoidFunction[]> = new Map();
|
const spoilersByMessageId: Map<number, VoidFunction[]> = new Map();
|
||||||
@ -18,22 +18,17 @@ const spoilersByMessageId: Map<number, VoidFunction[]> = new Map();
|
|||||||
const Spoiler: FC<OwnProps> = ({
|
const Spoiler: FC<OwnProps> = ({
|
||||||
children,
|
children,
|
||||||
messageId,
|
messageId,
|
||||||
isInactive,
|
|
||||||
}) => {
|
}) => {
|
||||||
const [isRevealed, reveal] = useFlag();
|
const [isRevealed, reveal] = useFlag();
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||||
if (!messageId) return;
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
spoilersByMessageId.get(messageId)?.forEach((_reveal) => _reveal());
|
spoilersByMessageId.get(messageId!)?.forEach((_reveal) => _reveal());
|
||||||
}, [messageId]);
|
}, [messageId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isRevealed && messageId) {
|
|
||||||
spoilersByMessageId.delete(messageId);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!messageId) {
|
if (!messageId) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -53,12 +48,14 @@ const Spoiler: FC<OwnProps> = ({
|
|||||||
<span
|
<span
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'Spoiler',
|
'Spoiler',
|
||||||
isRevealed && 'is-revealed',
|
!isRevealed && 'concealed',
|
||||||
!isInactive && 'animate',
|
!isRevealed && Boolean(messageId) && 'animated',
|
||||||
)}
|
)}
|
||||||
onClick={!isInactive && !isRevealed ? handleClick : undefined}
|
onClick={messageId && !isRevealed ? handleClick : undefined}
|
||||||
>
|
>
|
||||||
{children}
|
<span>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -430,7 +430,7 @@ const MediaViewer: FC<StateProps> = ({
|
|||||||
|
|
||||||
return captureEvents(element, {
|
return captureEvents(element, {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
excludedClosestSelector: `.backdrop, .navigation, .media-viewer-head, .media-viewer-footer${!shouldCloseOnVideo ? ', .VideoPlayer' : ''}`,
|
excludedClosestSelector: `.backdrop, .navigation, .media-viewer-head, .Spoiler, .media-viewer-footer${!shouldCloseOnVideo ? ', .VideoPlayer' : ''}`,
|
||||||
onClick: close,
|
onClick: close,
|
||||||
});
|
});
|
||||||
}, [close, isGif, isZoomed, messageId]);
|
}, [close, isGif, isZoomed, messageId]);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
getMessageMediaHash,
|
getMessageMediaHash,
|
||||||
getMessagePhoto,
|
getMessagePhoto,
|
||||||
getMessageText,
|
getMessageText,
|
||||||
|
getMessageTextWithSpoilers,
|
||||||
getMessageWebPagePhoto,
|
getMessageWebPagePhoto,
|
||||||
getMessageWebPageVideo,
|
getMessageWebPageVideo,
|
||||||
hasMessageLocalBlobUrl,
|
hasMessageLocalBlobUrl,
|
||||||
@ -52,7 +53,7 @@ export function getMessageCopyOptions(
|
|||||||
options.push({
|
options.push({
|
||||||
label: getCopyLabel(hasSelection),
|
label: getCopyLabel(hasSelection),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
const clipboardText = hasSelection && selection ? selection.toString() : text;
|
const clipboardText = hasSelection && selection ? selection.toString() : getMessageTextWithSpoilers(message)!;
|
||||||
copyTextToClipboard(clipboardText);
|
copyTextToClipboard(clipboardText);
|
||||||
|
|
||||||
if (afterEffect) {
|
if (afterEffect) {
|
||||||
|
|||||||
@ -15,30 +15,34 @@ export function getMessageSummaryText(
|
|||||||
) {
|
) {
|
||||||
const emoji = !noEmoji && getMessageSummaryEmoji(message);
|
const emoji = !noEmoji && getMessageSummaryEmoji(message);
|
||||||
const emojiWithSpace = emoji ? `${emoji} ` : '';
|
const emojiWithSpace = emoji ? `${emoji} ` : '';
|
||||||
|
const text = getMessageTextWithSpoilers(message)?.substr(0, truncateLength);
|
||||||
let text = getMessageText(message);
|
|
||||||
if (text) {
|
|
||||||
const { entities } = message.content.text || {};
|
|
||||||
if (entities?.length) {
|
|
||||||
text = entities.reduce((accText, { type, offset, length }) => {
|
|
||||||
if (type !== ApiMessageEntityTypes.Spoiler) {
|
|
||||||
return accText;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spoiler = generateBrailleSpoiler(length);
|
|
||||||
|
|
||||||
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
|
|
||||||
}, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
text = text.substr(0, truncateLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
const description = getMessageSummaryDescription(lang, message, text);
|
const description = getMessageSummaryDescription(lang, message, text);
|
||||||
|
|
||||||
return `${emojiWithSpace}${description}`;
|
return `${emojiWithSpace}${description}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMessageTextWithSpoilers(message: ApiMessage) {
|
||||||
|
const text = getMessageText(message);
|
||||||
|
if (!text) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { entities } = message.content.text || {};
|
||||||
|
if (!entities?.length) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities.reduce((accText, { type, offset, length }) => {
|
||||||
|
if (type !== ApiMessageEntityTypes.Spoiler) {
|
||||||
|
return accText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spoiler = generateBrailleSpoiler(length);
|
||||||
|
|
||||||
|
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
|
||||||
|
}, text);
|
||||||
|
}
|
||||||
|
|
||||||
export function getMessageSummaryEmoji(message: ApiMessage) {
|
export function getMessageSummaryEmoji(message: ApiMessage) {
|
||||||
const {
|
const {
|
||||||
photo, video, audio, voice, document, sticker, poll,
|
photo, video, audio, voice, document, sticker, poll,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user