Composer / Web Page Preview: Add animation, fix links with _, do not show title
This commit is contained in:
parent
987dfacaf5
commit
ca65c04884
@ -700,9 +700,12 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div id="message-compose">
|
||||
<div className="svg-appendix" ref={appendixRef} />
|
||||
<ComposerEmbeddedMessage />
|
||||
{allowedAttachmentOptions.canAttachEmbedLinks && (
|
||||
<WebPagePreview chatId={chatId} threadId={threadId} messageText={!attachments.length ? html : ''} />
|
||||
)}
|
||||
<WebPagePreview
|
||||
chatId={chatId}
|
||||
threadId={threadId}
|
||||
messageText={!attachments.length ? html : ''}
|
||||
disabled={!allowedAttachmentOptions.canAttachEmbedLinks}
|
||||
/>
|
||||
<div className="message-input-wrapper">
|
||||
{IS_MOBILE_SCREEN ? (
|
||||
<Button
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
.WebPagePreview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: -.75rem;
|
||||
padding-right: 0.625rem;
|
||||
padding-top: 0.45rem;
|
||||
height: 2.625rem;
|
||||
transition: height 150ms ease-out, opacity 150ms ease-out;
|
||||
|
||||
&:not(.open) {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 0.625rem;
|
||||
padding-top: 0.45rem;
|
||||
}
|
||||
|
||||
--accent-color: var(--color-primary);
|
||||
|
||||
@ -11,7 +19,7 @@
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
& > .Button {
|
||||
& > div > .Button {
|
||||
flex-shrink: 0;
|
||||
background: none !important;
|
||||
width: 2.125rem;
|
||||
@ -26,13 +34,18 @@
|
||||
margin: 0.1875rem 0 0.1875rem 0.125rem;
|
||||
|
||||
&::before {
|
||||
top: .125rem;
|
||||
bottom: .0625rem;
|
||||
bottom: .125rem;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
margin-top: .125rem;
|
||||
margin-bottom: 0.1875rem;
|
||||
}
|
||||
|
||||
.site-description {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,10 +6,14 @@ import { withGlobal } from '../../../lib/teact/teactn';
|
||||
import { GlobalActions } from '../../../global/types';
|
||||
import { ApiMessage, ApiMessageEntityTypes, ApiWebPage } from '../../../api/types';
|
||||
|
||||
import { RE_LINK_TEMPLATE } from '../../../config';
|
||||
import { selectNoWebPage } from '../../../modules/selectors';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import parseMessageInput from './helpers/parseMessageInput';
|
||||
import useOnChange from '../../../hooks/useOnChange';
|
||||
import useShowTransition from '../../../hooks/useShowTransition';
|
||||
import usePrevForAnimation from '../../../hooks/usePrevForAnimation';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
import WebPage from '../message/WebPage';
|
||||
import Button from '../../ui/Button';
|
||||
@ -20,6 +24,7 @@ type OwnProps = {
|
||||
chatId: number;
|
||||
threadId: number;
|
||||
messageText: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
@ -28,12 +33,13 @@ type StateProps = {
|
||||
};
|
||||
type DispatchProps = Pick<GlobalActions, 'loadWebPagePreview' | 'clearWebPagePreview' | 'toggleMessageWebPage'>;
|
||||
|
||||
const RE_LINK = /https?:\/\/(www.)?([a-zA-Z0-9.-]{2,256})([a-zA-Z/.-]{1,256})([?|#][=&#a-zA-Z0-9]{2,128})?/;
|
||||
const RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');
|
||||
|
||||
const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
chatId,
|
||||
threadId,
|
||||
messageText,
|
||||
disabled,
|
||||
webPagePreview,
|
||||
noWebPage,
|
||||
loadWebPagePreview,
|
||||
@ -70,16 +76,21 @@ const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
toggleMessageWebPage({ chatId, threadId });
|
||||
}, [chatId]);
|
||||
|
||||
const isShown = Boolean(webPagePreview && messageText.length && !noWebPage && !disabled);
|
||||
const { shouldRender, transitionClassNames } = useShowTransition(isShown);
|
||||
|
||||
const renderingWebPage = usePrevForAnimation(webPagePreview);
|
||||
|
||||
if (!shouldRender || !renderingWebPage) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const handleClearWebpagePreview = () => {
|
||||
toggleMessageWebPage({ chatId, threadId, noWebPage: true });
|
||||
};
|
||||
|
||||
if (!webPagePreview || !messageText.length || noWebPage) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// TODO Refactor so `WebPage` can be used without message
|
||||
const { photo, ...webPageWithoutPhoto } = webPagePreview;
|
||||
const { photo, ...webPageWithoutPhoto } = renderingWebPage;
|
||||
const messageStub = {
|
||||
content: {
|
||||
webPage: webPageWithoutPhoto,
|
||||
@ -87,11 +98,13 @@ const WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
} as ApiMessage;
|
||||
|
||||
return (
|
||||
<div className="WebPagePreview">
|
||||
<Button round color="translucent" ariaLabel="Clear Webpage Preview" onClick={handleClearWebpagePreview}>
|
||||
<i className="icon-close" />
|
||||
</Button>
|
||||
<WebPage message={messageStub} inPreview />
|
||||
<div className={buildClassName('WebPagePreview', transitionClassNames)}>
|
||||
<div>
|
||||
<Button round color="translucent" ariaLabel="Clear Webpage Preview" onClick={handleClearWebpagePreview}>
|
||||
<i className="icon-close" />
|
||||
</Button>
|
||||
<WebPage message={messageStub} inPreview />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -19,6 +19,12 @@
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.media-inner {
|
||||
margin: 0 !important;
|
||||
margin-bottom: 0.375rem !important;
|
||||
@ -77,6 +83,7 @@
|
||||
.site-name {
|
||||
color: var(--accent-color);
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.125rem;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import React, { FC, memo, useCallback } from '../../../lib/teact/teact';
|
||||
|
||||
import { ApiMessage } from '../../../api/types';
|
||||
import { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
|
||||
import { getMessageWebPage } from '../../../modules/helpers';
|
||||
import { calculateMediaDimensions } from './helpers/mediaDimensions';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
import trimText from '../../../util/trimText';
|
||||
import { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
import SafeLink from '../../common/SafeLink';
|
||||
import Photo from './Photo';
|
||||
@ -63,12 +64,12 @@ const WebPage: FC<OwnProps> = ({
|
||||
|
||||
const truncatedDescription = trimText(description, MAX_TEXT_LENGTH);
|
||||
|
||||
const className = [
|
||||
const className = buildClassName(
|
||||
'WebPage',
|
||||
photo
|
||||
? (isSquarePhoto && 'with-square-photo')
|
||||
: (!inPreview && 'without-photo'),
|
||||
].filter(Boolean).join(' ');
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -87,7 +88,7 @@ const WebPage: FC<OwnProps> = ({
|
||||
)}
|
||||
<div className="WebPage-text">
|
||||
<SafeLink className="site-name" url={url} text={siteName || displayUrl} />
|
||||
{title && (
|
||||
{!inPreview && title && (
|
||||
<p className="site-title">{renderText(title)}</p>
|
||||
)}
|
||||
{truncatedDescription && (
|
||||
|
||||
@ -26,5 +26,5 @@ export default function usePrevForAnimation(current: any, duration?: number) {
|
||||
}
|
||||
}, [current]);
|
||||
|
||||
return !timeoutRef.current || !duration || isCurrentPresent ? current : prev;
|
||||
return isCurrentPresent || (duration && !timeoutRef.current) ? current : prev;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user