Web Page: Send inverted web page; Web Page menu (#4701)
This commit is contained in:
parent
cf4c562408
commit
5fb1283884
@ -25,6 +25,7 @@ import type {
|
|||||||
ApiTopic,
|
ApiTopic,
|
||||||
ApiUser,
|
ApiUser,
|
||||||
ApiVideo,
|
ApiVideo,
|
||||||
|
ApiWebPage,
|
||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type {
|
import type {
|
||||||
ApiDraft, GlobalState, MessageList,
|
ApiDraft, GlobalState, MessageList,
|
||||||
@ -75,6 +76,7 @@ import {
|
|||||||
selectIsReactionPickerOpen,
|
selectIsReactionPickerOpen,
|
||||||
selectIsRightColumnShown,
|
selectIsRightColumnShown,
|
||||||
selectNewestMessageWithBotKeyboardButtons,
|
selectNewestMessageWithBotKeyboardButtons,
|
||||||
|
selectNoWebPage,
|
||||||
selectPeerStory,
|
selectPeerStory,
|
||||||
selectRequestedDraft,
|
selectRequestedDraft,
|
||||||
selectRequestedDraftFiles,
|
selectRequestedDraftFiles,
|
||||||
@ -249,6 +251,8 @@ type StateProps =
|
|||||||
quickReplyMessages?: Record<number, ApiMessage>;
|
quickReplyMessages?: Record<number, ApiMessage>;
|
||||||
quickReplies?: Record<number, ApiQuickReply>;
|
quickReplies?: Record<number, ApiQuickReply>;
|
||||||
canSendQuickReplies?: boolean;
|
canSendQuickReplies?: boolean;
|
||||||
|
webPagePreview?: ApiWebPage;
|
||||||
|
noWebPage?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MainButtonState {
|
enum MainButtonState {
|
||||||
@ -355,6 +359,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
quickReplies,
|
quickReplies,
|
||||||
canSendQuickReplies,
|
canSendQuickReplies,
|
||||||
onForward,
|
onForward,
|
||||||
|
webPagePreview,
|
||||||
|
noWebPage,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
@ -377,6 +383,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
closeReactionPicker,
|
closeReactionPicker,
|
||||||
sendStoryReaction,
|
sendStoryReaction,
|
||||||
editMessage,
|
editMessage,
|
||||||
|
updateAttachmentSettings,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
@ -466,8 +473,15 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
[chat, chatFullInfo, isChatWithBot, isInStoryViewer],
|
[chat, chatFullInfo, isChatWithBot, isInStoryViewer],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasWebPagePreview = !hasAttachments && canAttachEmbedLinks && !noWebPage && Boolean(webPagePreview);
|
||||||
const isComposerBlocked = !canSendPlainText && !editingMessage;
|
const isComposerBlocked = !canSendPlainText && !editingMessage;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasWebPagePreview) {
|
||||||
|
updateAttachmentSettings({ isInvertedMedia: undefined });
|
||||||
|
}
|
||||||
|
}, [hasWebPagePreview]);
|
||||||
|
|
||||||
const insertHtmlAndUpdateCursor = useLastCallback((newHtml: string, inInputId: string = editableInputId) => {
|
const insertHtmlAndUpdateCursor = useLastCallback((newHtml: string, inInputId: string = editableInputId) => {
|
||||||
if (inInputId === editableInputId && isComposerBlocked) return;
|
if (inInputId === editableInputId && isComposerBlocked) return;
|
||||||
const selection = window.getSelection()!;
|
const selection = window.getSelection()!;
|
||||||
@ -1012,6 +1026,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
if (text) {
|
if (text) {
|
||||||
if (!checkSlowMode()) return;
|
if (!checkSlowMode()) return;
|
||||||
|
|
||||||
|
const isInvertedMedia = hasWebPagePreview ? attachmentSettings.isInvertedMedia : undefined;
|
||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
messageList: currentMessageList,
|
messageList: currentMessageList,
|
||||||
text,
|
text,
|
||||||
@ -1019,6 +1035,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
scheduledAt,
|
scheduledAt,
|
||||||
isSilent,
|
isSilent,
|
||||||
shouldUpdateStickerSetOrder,
|
shouldUpdateStickerSetOrder,
|
||||||
|
isInvertedMedia,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,6 +1701,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
threadId={threadId}
|
threadId={threadId}
|
||||||
getHtml={getHtml}
|
getHtml={getHtml}
|
||||||
isDisabled={!canAttachEmbedLinks || hasAttachments}
|
isDisabled={!canAttachEmbedLinks || hasAttachments}
|
||||||
|
isEditing={Boolean(editingMessage)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -2048,6 +2066,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
const canSendQuickReplies = isChatWithUser && !isChatWithBot && !isInScheduledList && !isChatWithSelf;
|
const canSendQuickReplies = isChatWithUser && !isChatWithBot && !isInScheduledList && !isChatWithSelf;
|
||||||
|
|
||||||
|
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
availableReactions: type === 'story' ? global.reactions.availableReactions : undefined,
|
availableReactions: type === 'story' ? global.reactions.availableReactions : undefined,
|
||||||
topReactions: type === 'story' ? global.reactions.topReactions : undefined,
|
topReactions: type === 'story' ? global.reactions.topReactions : undefined,
|
||||||
@ -2115,6 +2135,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
quickReplyMessages: global.quickReplies.messagesById,
|
quickReplyMessages: global.quickReplies.messagesById,
|
||||||
quickReplies: global.quickReplies.byId,
|
quickReplies: global.quickReplies.byId,
|
||||||
canSendQuickReplies,
|
canSendQuickReplies,
|
||||||
|
noWebPage,
|
||||||
|
webPagePreview: selectTabState(global).webPagePreview,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Composer));
|
)(Composer));
|
||||||
|
|||||||
@ -167,7 +167,7 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
|||||||
(shouldSendCompressed || shouldForceCompression || isInAlbum) && !shouldForceAsFile,
|
(shouldSendCompressed || shouldForceCompression || isInAlbum) && !shouldForceAsFile,
|
||||||
);
|
);
|
||||||
const [shouldSendGrouped, setShouldSendGrouped] = useState(attachmentSettings.shouldSendGrouped);
|
const [shouldSendGrouped, setShouldSendGrouped] = useState(attachmentSettings.shouldSendGrouped);
|
||||||
const [isInvertedMedia, setIsInvertedMedia] = useState(attachmentSettings.isInvertedMedia);
|
const isInvertedMedia = attachmentSettings.isInvertedMedia;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleScroll: handleAttachmentsScroll,
|
handleScroll: handleAttachmentsScroll,
|
||||||
@ -184,6 +184,7 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
closeSymbolMenu();
|
closeSymbolMenu();
|
||||||
|
updateAttachmentSettings({ isInvertedMedia: undefined });
|
||||||
}
|
}
|
||||||
}, [closeSymbolMenu, isOpen]);
|
}, [closeSymbolMenu, isOpen]);
|
||||||
|
|
||||||
@ -254,10 +255,19 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
|||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
setShouldSendCompressed(shouldSuggestCompression ?? attachmentSettings.shouldCompress);
|
setShouldSendCompressed(shouldSuggestCompression ?? attachmentSettings.shouldCompress);
|
||||||
setShouldSendGrouped(attachmentSettings.shouldSendGrouped);
|
setShouldSendGrouped(attachmentSettings.shouldSendGrouped);
|
||||||
setIsInvertedMedia(attachmentSettings.isInvertedMedia);
|
|
||||||
}
|
}
|
||||||
}, [attachmentSettings, isOpen, shouldSuggestCompression]);
|
}, [attachmentSettings, isOpen, shouldSuggestCompression]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen) {
|
||||||
|
updateAttachmentSettings({ isInvertedMedia: undefined });
|
||||||
|
}
|
||||||
|
}, [updateAttachmentSettings, isOpen, shouldSuggestCompression]);
|
||||||
|
|
||||||
|
function setIsInvertedMedia(value?: true) {
|
||||||
|
updateAttachmentSettings({ isInvertedMedia: value });
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen && isMobile) {
|
if (isOpen && isMobile) {
|
||||||
removeAllSelections();
|
removeAllSelections();
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
.WebPagePreview {
|
.WebPagePreview {
|
||||||
|
position: relative;
|
||||||
height: 3.125rem;
|
height: 3.125rem;
|
||||||
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
||||||
transition: height 150ms ease-out, opacity 150ms ease-out;
|
transition: height 150ms ease-out, opacity 150ms ease-out;
|
||||||
@ -30,6 +31,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.web-page-preview-context-menu {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-placeholder {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& &-left-icon {
|
& &-left-icon {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background: none !important;
|
background: none !important;
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, { memo, useEffect, useRef } from '../../../lib/teact/teact';
|
import React, {
|
||||||
|
memo, useEffect, useRef,
|
||||||
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiFormattedText, ApiMessage, ApiMessageEntityTextUrl, ApiWebPage,
|
ApiFormattedText, ApiMessage, ApiMessageEntityTextUrl, ApiWebPage,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
import type { GlobalState } from '../../../global/types';
|
||||||
import type { ISettings, ThreadId } from '../../../types';
|
import type { ISettings, ThreadId } from '../../../types';
|
||||||
import type { Signal } from '../../../util/signals';
|
import type { Signal } from '../../../util/signals';
|
||||||
import { ApiMessageEntityTypes } from '../../../api/types';
|
import { ApiMessageEntityTypes } from '../../../api/types';
|
||||||
@ -15,14 +18,19 @@ import buildClassName from '../../../util/buildClassName';
|
|||||||
import parseHtmlAsFormattedText from '../../../util/parseHtmlAsFormattedText';
|
import parseHtmlAsFormattedText from '../../../util/parseHtmlAsFormattedText';
|
||||||
|
|
||||||
import { useDebouncedResolver } from '../../../hooks/useAsyncResolvers';
|
import { useDebouncedResolver } from '../../../hooks/useAsyncResolvers';
|
||||||
|
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||||
import useDerivedSignal from '../../../hooks/useDerivedSignal';
|
import useDerivedSignal from '../../../hooks/useDerivedSignal';
|
||||||
import useDerivedState from '../../../hooks/useDerivedState';
|
import useDerivedState from '../../../hooks/useDerivedState';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
import useMenuPosition from '../../../hooks/useMenuPosition';
|
||||||
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
import useSyncEffect from '../../../hooks/useSyncEffect';
|
import useSyncEffect from '../../../hooks/useSyncEffect';
|
||||||
|
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
|
import Menu from '../../ui/Menu';
|
||||||
|
import MenuItem from '../../ui/MenuItem';
|
||||||
import WebPage from '../message/WebPage';
|
import WebPage from '../message/WebPage';
|
||||||
|
|
||||||
import './WebPagePreview.scss';
|
import './WebPagePreview.scss';
|
||||||
@ -31,6 +39,7 @@ type OwnProps = {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
threadId: ThreadId;
|
threadId: ThreadId;
|
||||||
getHtml: Signal<string>;
|
getHtml: Signal<string>;
|
||||||
|
isEditing: boolean;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,6 +47,7 @@ type StateProps = {
|
|||||||
webPagePreview?: ApiWebPage;
|
webPagePreview?: ApiWebPage;
|
||||||
noWebPage?: boolean;
|
noWebPage?: boolean;
|
||||||
theme: ISettings['theme'];
|
theme: ISettings['theme'];
|
||||||
|
attachmentSettings: GlobalState['attachmentSettings'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEBOUNCE_MS = 300;
|
const DEBOUNCE_MS = 300;
|
||||||
@ -51,15 +61,25 @@ const WebPagePreview: FC<OwnProps & StateProps> = ({
|
|||||||
webPagePreview,
|
webPagePreview,
|
||||||
noWebPage,
|
noWebPage,
|
||||||
theme,
|
theme,
|
||||||
|
attachmentSettings,
|
||||||
|
isEditing,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
loadWebPagePreview,
|
loadWebPagePreview,
|
||||||
clearWebPagePreview,
|
clearWebPagePreview,
|
||||||
toggleMessageWebPage,
|
toggleMessageWebPage,
|
||||||
|
updateAttachmentSettings,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
|
const lang = useOldLang();
|
||||||
|
|
||||||
const formattedTextWithLinkRef = useRef<ApiFormattedText>();
|
const formattedTextWithLinkRef = useRef<ApiFormattedText>();
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const isInvertedMedia = attachmentSettings.isInvertedMedia;
|
||||||
|
|
||||||
const detectLinkDebounced = useDebouncedResolver(() => {
|
const detectLinkDebounced = useDebouncedResolver(() => {
|
||||||
const formattedText = parseHtmlAsFormattedText(getHtml());
|
const formattedText = parseHtmlAsFormattedText(getHtml());
|
||||||
const linkEntity = formattedText.entities?.find((entity): entity is ApiMessageEntityTextUrl => (
|
const linkEntity = formattedText.entities?.find((entity): entity is ApiMessageEntityTextUrl => (
|
||||||
@ -101,6 +121,41 @@ const WebPagePreview: FC<OwnProps & StateProps> = ({
|
|||||||
toggleMessageWebPage({ chatId, threadId, noWebPage: true });
|
toggleMessageWebPage({ chatId, threadId, noWebPage: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
isContextMenuOpen, contextMenuPosition, handleContextMenu,
|
||||||
|
handleContextMenuClose, handleContextMenuHide,
|
||||||
|
} = useContextMenuHandlers(ref, isEditing, true);
|
||||||
|
|
||||||
|
const getTriggerElement = useLastCallback(() => ref.current);
|
||||||
|
const getRootElement = useLastCallback(() => ref.current!);
|
||||||
|
const getMenuElement = useLastCallback(
|
||||||
|
() => ref.current!.querySelector('.web-page-preview-context-menu .bubble'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
positionX, positionY, transformOriginX, transformOriginY, style: menuStyle,
|
||||||
|
} = useMenuPosition(
|
||||||
|
contextMenuPosition,
|
||||||
|
getTriggerElement,
|
||||||
|
getRootElement,
|
||||||
|
getMenuElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlePreviewClick = useLastCallback((e: React.MouseEvent): void => {
|
||||||
|
handleContextMenu(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shouldRender || !renderingWebPage) {
|
||||||
|
handleContextMenuClose();
|
||||||
|
handleContextMenuHide();
|
||||||
|
}
|
||||||
|
}, [handleContextMenuClose, handleContextMenuHide, shouldRender, renderingWebPage]);
|
||||||
|
|
||||||
|
function updateIsInvertedMedia(value?: true) {
|
||||||
|
updateAttachmentSettings({ isInvertedMedia: value });
|
||||||
|
}
|
||||||
|
|
||||||
if (!shouldRender || !renderingWebPage) {
|
if (!shouldRender || !renderingWebPage) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -113,13 +168,59 @@ const WebPagePreview: FC<OwnProps & StateProps> = ({
|
|||||||
},
|
},
|
||||||
} as ApiMessage;
|
} as ApiMessage;
|
||||||
|
|
||||||
|
function renderContextMenu() {
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
isOpen={isContextMenuOpen}
|
||||||
|
transformOriginX={transformOriginX}
|
||||||
|
transformOriginY={transformOriginY}
|
||||||
|
positionX={positionX}
|
||||||
|
positionY={positionY}
|
||||||
|
style={menuStyle}
|
||||||
|
className="web-page-preview-context-menu"
|
||||||
|
onClose={handleContextMenuClose}
|
||||||
|
onCloseAnimationEnd={handleContextMenuHide}
|
||||||
|
autoClose
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
isInvertedMedia ? (
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
<MenuItem icon="move-caption-up" onClick={() => updateIsInvertedMedia(undefined)}>
|
||||||
|
{lang('PreviewSender.MoveTextUp')}
|
||||||
|
</MenuItem>
|
||||||
|
) : (
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
<MenuItem icon="move-caption-down" onClick={() => updateIsInvertedMedia(true)}>
|
||||||
|
{lang(('PreviewSender.MoveTextDown'))}
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<MenuItem
|
||||||
|
icon="delete"
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
|
onClick={handleClearWebpagePreview}
|
||||||
|
>
|
||||||
|
{lang('ChatInput.EditLink.RemovePreview')}
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={buildClassName('WebPagePreview', transitionClassNames)}>
|
<div className={buildClassName('WebPagePreview', transitionClassNames)} ref={ref}>
|
||||||
<div className="WebPagePreview_inner">
|
<div className="WebPagePreview_inner">
|
||||||
<div className="WebPagePreview-left-icon">
|
<div className="WebPagePreview-left-icon" onClick={handlePreviewClick}>
|
||||||
<i className="icon icon-link" />
|
<i className="icon icon-link" />
|
||||||
</div>
|
</div>
|
||||||
<WebPage message={messageStub} inPreview theme={theme} />
|
<WebPage
|
||||||
|
message={messageStub}
|
||||||
|
inPreview
|
||||||
|
theme={theme}
|
||||||
|
onContainerClick={handlePreviewClick}
|
||||||
|
isEditing={isEditing}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
className="WebPagePreview-clear"
|
className="WebPagePreview-clear"
|
||||||
round
|
round
|
||||||
@ -130,6 +231,7 @@ const WebPagePreview: FC<OwnProps & StateProps> = ({
|
|||||||
>
|
>
|
||||||
<i className="icon icon-close" />
|
<i className="icon icon-close" />
|
||||||
</Button>
|
</Button>
|
||||||
|
{!isEditing && renderContextMenu()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -138,10 +240,14 @@ const WebPagePreview: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId, threadId }): StateProps => {
|
(global, { chatId, threadId }): StateProps => {
|
||||||
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
const noWebPage = selectNoWebPage(global, chatId, threadId);
|
||||||
|
const {
|
||||||
|
attachmentSettings,
|
||||||
|
} = global;
|
||||||
return {
|
return {
|
||||||
theme: selectTheme(global),
|
theme: selectTheme(global),
|
||||||
webPagePreview: selectTabState(global).webPagePreview,
|
webPagePreview: selectTabState(global).webPagePreview,
|
||||||
noWebPage,
|
noWebPage,
|
||||||
|
attachmentSettings,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(WebPagePreview));
|
)(WebPagePreview));
|
||||||
|
|||||||
@ -49,6 +49,13 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.125rem 0.25rem 0.125rem 0.625rem;
|
padding: 0.125rem 0.25rem 0.125rem 0.625rem;
|
||||||
transition: background-color 0.2s ease-in;
|
transition: background-color 0.2s ease-in;
|
||||||
|
|
||||||
|
&.interactive {
|
||||||
|
cursor: var(--custom-cursor, pointer);
|
||||||
|
&:active {
|
||||||
|
background-color: var(--background-active-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
|||||||
@ -56,6 +56,8 @@ type OwnProps = {
|
|||||||
onAudioPlay?: NoneToVoidFunction;
|
onAudioPlay?: NoneToVoidFunction;
|
||||||
onMediaClick?: NoneToVoidFunction;
|
onMediaClick?: NoneToVoidFunction;
|
||||||
onCancelMediaTransfer?: NoneToVoidFunction;
|
onCancelMediaTransfer?: NoneToVoidFunction;
|
||||||
|
onContainerClick?: ((e: React.MouseEvent) => void);
|
||||||
|
isEditing?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const WebPage: FC<OwnProps> = ({
|
const WebPage: FC<OwnProps> = ({
|
||||||
@ -76,8 +78,10 @@ const WebPage: FC<OwnProps> = ({
|
|||||||
shouldWarnAboutSvg,
|
shouldWarnAboutSvg,
|
||||||
autoLoadFileMaxSizeMb,
|
autoLoadFileMaxSizeMb,
|
||||||
onMediaClick,
|
onMediaClick,
|
||||||
|
onContainerClick,
|
||||||
onAudioPlay,
|
onAudioPlay,
|
||||||
onCancelMediaTransfer,
|
onCancelMediaTransfer,
|
||||||
|
isEditing,
|
||||||
}) => {
|
}) => {
|
||||||
const { openTelegramLink } = getActions();
|
const { openTelegramLink } = getActions();
|
||||||
const webPage = getMessageWebPage(message);
|
const webPage = getMessageWebPage(message);
|
||||||
@ -92,6 +96,9 @@ const WebPage: FC<OwnProps> = ({
|
|||||||
const handleMediaClick = useLastCallback(() => {
|
const handleMediaClick = useLastCallback(() => {
|
||||||
onMediaClick!();
|
onMediaClick!();
|
||||||
});
|
});
|
||||||
|
const handleContainerClick = useLastCallback((e: React.MouseEvent) => {
|
||||||
|
onContainerClick?.(e);
|
||||||
|
});
|
||||||
|
|
||||||
const handleQuickButtonClick = useLastCallback(() => {
|
const handleQuickButtonClick = useLastCallback(() => {
|
||||||
if (!webPage) return;
|
if (!webPage) return;
|
||||||
@ -138,6 +145,7 @@ const WebPage: FC<OwnProps> = ({
|
|||||||
const className = buildClassName(
|
const className = buildClassName(
|
||||||
'WebPage',
|
'WebPage',
|
||||||
inPreview && 'in-preview',
|
inPreview && 'in-preview',
|
||||||
|
!isEditing && inPreview && 'interactive',
|
||||||
isSquarePhoto && 'with-square-photo',
|
isSquarePhoto && 'with-square-photo',
|
||||||
!photo && !video && !inPreview && 'without-media',
|
!photo && !video && !inPreview && 'without-media',
|
||||||
video && 'with-video',
|
video && 'with-video',
|
||||||
@ -166,6 +174,7 @@ const WebPage: FC<OwnProps> = ({
|
|||||||
className={className}
|
className={className}
|
||||||
data-initial={(siteName || displayUrl)[0]}
|
data-initial={(siteName || displayUrl)[0]}
|
||||||
dir={lang.isRtl ? 'rtl' : 'auto'}
|
dir={lang.isRtl ? 'rtl' : 'auto'}
|
||||||
|
onClick={handleContainerClick}
|
||||||
>
|
>
|
||||||
<div className={buildClassName('WebPage--content', isStory && 'is-story')}>
|
<div className={buildClassName('WebPage--content', isStory && 'is-story')}>
|
||||||
{backgroundEmojiId && (
|
{backgroundEmojiId && (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user