Fix collapsed corners for link previews and image attachments
This commit is contained in:
parent
65dc9d6afb
commit
9d3498d938
9 changed files with 260 additions and 181 deletions
|
@ -779,7 +779,7 @@
|
|||
width: calc(100% + 24px);
|
||||
outline: none;
|
||||
|
||||
margin-top: -10px;
|
||||
margin-top: -8px;
|
||||
margin-bottom: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
|
@ -2492,30 +2492,10 @@ button.ConversationDetails__action-button {
|
|||
left: 6px;
|
||||
}
|
||||
|
||||
.module-image--soft-corners {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.module-image--cropped {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.module-image--curved-top-left {
|
||||
border-top-left-radius: 18px;
|
||||
}
|
||||
.module-image--curved-top-right {
|
||||
border-top-right-radius: 18px;
|
||||
}
|
||||
.module-image--curved-bottom-left {
|
||||
border-bottom-left-radius: 18px;
|
||||
}
|
||||
.module-image--curved-bottom-right {
|
||||
border-bottom-right-radius: 18px;
|
||||
}
|
||||
.module-image--small-curved-top-left {
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.module-image__border-overlay {
|
||||
@include button-reset;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { Image } from './Image';
|
||||
import { CurveType, Image } from './Image';
|
||||
import { StagedGenericAttachment } from './StagedGenericAttachment';
|
||||
import { StagedPlaceholderAttachment } from './StagedPlaceholderAttachment';
|
||||
import type { LocalizerType } from '../../types/Util';
|
||||
|
@ -109,7 +109,10 @@ export const AttachmentList = <T extends AttachmentType | AttachmentDraftType>({
|
|||
i18n={i18n}
|
||||
attachment={attachment}
|
||||
isDownloaded={isDownloaded}
|
||||
softCorners
|
||||
curveBottomLeft={CurveType.Tiny}
|
||||
curveBottomRight={CurveType.Tiny}
|
||||
curveTopLeft={CurveType.Tiny}
|
||||
curveTopRight={CurveType.Tiny}
|
||||
playIconOverlay={isVideo}
|
||||
height={IMAGE_HEIGHT}
|
||||
width={IMAGE_WIDTH}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { storiesOf } from '@storybook/react';
|
|||
|
||||
import { pngUrl } from '../../storybook/Fixtures';
|
||||
import type { Props } from './Image';
|
||||
import { Image } from './Image';
|
||||
import { CurveType, Image } from './Image';
|
||||
import { IMAGE_PNG } from '../../types/MIME';
|
||||
import type { ThemeType } from '../../types/Util';
|
||||
import { setupI18n } from '../../util/setupI18n';
|
||||
|
@ -34,16 +34,22 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
blurHash: text('blurHash', overrideProps.blurHash || ''),
|
||||
bottomOverlay: boolean('bottomOverlay', overrideProps.bottomOverlay || false),
|
||||
closeButton: boolean('closeButton', overrideProps.closeButton || false),
|
||||
curveBottomLeft: boolean(
|
||||
curveBottomLeft: number(
|
||||
'curveBottomLeft',
|
||||
overrideProps.curveBottomLeft || false
|
||||
overrideProps.curveBottomLeft || CurveType.None
|
||||
),
|
||||
curveBottomRight: boolean(
|
||||
curveBottomRight: number(
|
||||
'curveBottomRight',
|
||||
overrideProps.curveBottomRight || false
|
||||
overrideProps.curveBottomRight || CurveType.None
|
||||
),
|
||||
curveTopLeft: number(
|
||||
'curveTopLeft',
|
||||
overrideProps.curveTopLeft || CurveType.None
|
||||
),
|
||||
curveTopRight: number(
|
||||
'curveTopRight',
|
||||
overrideProps.curveTopRight || CurveType.None
|
||||
),
|
||||
curveTopLeft: boolean('curveTopLeft', overrideProps.curveTopLeft || false),
|
||||
curveTopRight: boolean('curveTopRight', overrideProps.curveTopRight || false),
|
||||
darkOverlay: boolean('darkOverlay', overrideProps.darkOverlay || false),
|
||||
height: number('height', overrideProps.height || 100),
|
||||
i18n,
|
||||
|
@ -57,11 +63,6 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
'playIconOverlay',
|
||||
overrideProps.playIconOverlay || false
|
||||
),
|
||||
smallCurveTopLeft: boolean(
|
||||
'smallCurveTopLeft',
|
||||
overrideProps.smallCurveTopLeft || false
|
||||
),
|
||||
softCorners: boolean('softCorners', overrideProps.softCorners || false),
|
||||
tabIndex: number('tabIndex', overrideProps.tabIndex || 0),
|
||||
theme: text('theme', overrideProps.theme || 'light') as ThemeType,
|
||||
url: text('url', 'url' in overrideProps ? overrideProps.url || null : pngUrl),
|
||||
|
@ -145,10 +146,10 @@ story.add('Pending w/blurhash', () => {
|
|||
|
||||
story.add('Curved Corners', () => {
|
||||
const props = createProps({
|
||||
curveBottomLeft: true,
|
||||
curveBottomRight: true,
|
||||
curveTopLeft: true,
|
||||
curveTopRight: true,
|
||||
curveBottomLeft: CurveType.Normal,
|
||||
curveBottomRight: CurveType.Normal,
|
||||
curveTopLeft: CurveType.Normal,
|
||||
curveTopRight: CurveType.Normal,
|
||||
});
|
||||
|
||||
return <Image {...props} />;
|
||||
|
@ -156,7 +157,7 @@ story.add('Curved Corners', () => {
|
|||
|
||||
story.add('Small Curve Top Left', () => {
|
||||
const props = createProps({
|
||||
smallCurveTopLeft: true,
|
||||
curveTopLeft: CurveType.Small,
|
||||
});
|
||||
|
||||
return <Image {...props} />;
|
||||
|
@ -164,7 +165,10 @@ story.add('Small Curve Top Left', () => {
|
|||
|
||||
story.add('Soft Corners', () => {
|
||||
const props = createProps({
|
||||
softCorners: true,
|
||||
curveBottomLeft: CurveType.Tiny,
|
||||
curveBottomRight: CurveType.Tiny,
|
||||
curveTopLeft: CurveType.Tiny,
|
||||
curveTopRight: CurveType.Tiny,
|
||||
});
|
||||
|
||||
return <Image {...props} />;
|
||||
|
|
|
@ -13,6 +13,13 @@ import {
|
|||
defaultBlurHash,
|
||||
} from '../../types/Attachment';
|
||||
|
||||
export enum CurveType {
|
||||
None = 0,
|
||||
Tiny = 4,
|
||||
Small = 10,
|
||||
Normal = 18,
|
||||
}
|
||||
|
||||
export type Props = {
|
||||
alt: string;
|
||||
attachment: AttachmentType;
|
||||
|
@ -32,16 +39,13 @@ export type Props = {
|
|||
noBackground?: boolean;
|
||||
bottomOverlay?: boolean;
|
||||
closeButton?: boolean;
|
||||
curveBottomLeft?: boolean;
|
||||
curveBottomRight?: boolean;
|
||||
curveTopLeft?: boolean;
|
||||
curveTopRight?: boolean;
|
||||
|
||||
smallCurveTopLeft?: boolean;
|
||||
curveBottomLeft?: CurveType;
|
||||
curveBottomRight?: CurveType;
|
||||
curveTopLeft?: CurveType;
|
||||
curveTopRight?: CurveType;
|
||||
|
||||
darkOverlay?: boolean;
|
||||
playIconOverlay?: boolean;
|
||||
softCorners?: boolean;
|
||||
blurHash?: string;
|
||||
|
||||
i18n: LocalizerType;
|
||||
|
@ -158,8 +162,6 @@ export class Image extends React.Component<Props> {
|
|||
onError,
|
||||
overlayText,
|
||||
playIconOverlay,
|
||||
smallCurveTopLeft,
|
||||
softCorners,
|
||||
tabIndex,
|
||||
theme,
|
||||
url,
|
||||
|
@ -176,25 +178,25 @@ export class Image extends React.Component<Props> {
|
|||
|
||||
const resolvedBlurHash = blurHash || defaultBlurHash(theme);
|
||||
|
||||
const overlayClassName = classNames('module-image__border-overlay', {
|
||||
'module-image__border-overlay--with-border': !noBorder,
|
||||
'module-image__border-overlay--with-click-handler': canClick,
|
||||
'module-image--curved-top-left': curveTopLeft,
|
||||
'module-image--curved-top-right': curveTopRight,
|
||||
'module-image--curved-bottom-left': curveBottomLeft,
|
||||
'module-image--curved-bottom-right': curveBottomRight,
|
||||
'module-image--small-curved-top-left': smallCurveTopLeft,
|
||||
'module-image--soft-corners': softCorners,
|
||||
'module-image__border-overlay--dark': darkOverlay,
|
||||
'module-image--not-downloaded': imgNotDownloaded,
|
||||
});
|
||||
const curveStyles = {
|
||||
borderTopLeftRadius: curveTopLeft || CurveType.None,
|
||||
borderTopRightRadius: curveTopRight || CurveType.None,
|
||||
borderBottomLeftRadius: curveBottomLeft || CurveType.None,
|
||||
borderBottomRightRadius: curveBottomRight || CurveType.None,
|
||||
};
|
||||
|
||||
const overlay = canClick ? (
|
||||
// Not sure what this button does.
|
||||
// eslint-disable-next-line jsx-a11y/control-has-associated-label
|
||||
<button
|
||||
type="button"
|
||||
className={overlayClassName}
|
||||
className={classNames('module-image__border-overlay', {
|
||||
'module-image__border-overlay--with-border': !noBorder,
|
||||
'module-image__border-overlay--with-click-handler': canClick,
|
||||
'module-image__border-overlay--dark': darkOverlay,
|
||||
'module-image--not-downloaded': imgNotDownloaded,
|
||||
})}
|
||||
style={curveStyles}
|
||||
onClick={this.handleClick}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
tabIndex={tabIndex}
|
||||
|
@ -210,15 +212,13 @@ export class Image extends React.Component<Props> {
|
|||
'module-image',
|
||||
className,
|
||||
!noBackground ? 'module-image--with-background' : null,
|
||||
curveBottomLeft ? 'module-image--curved-bottom-left' : null,
|
||||
curveBottomRight ? 'module-image--curved-bottom-right' : null,
|
||||
curveTopLeft ? 'module-image--curved-top-left' : null,
|
||||
curveTopRight ? 'module-image--curved-top-right' : null,
|
||||
smallCurveTopLeft ? 'module-image--small-curved-top-left' : null,
|
||||
softCorners ? 'module-image--soft-corners' : null,
|
||||
cropWidth || cropHeight ? 'module-image--cropped' : null
|
||||
)}
|
||||
style={{ width: width - cropWidth, height: height - cropHeight }}
|
||||
style={{
|
||||
width: width - cropWidth,
|
||||
height: height - cropHeight,
|
||||
...curveStyles,
|
||||
}}
|
||||
>
|
||||
{pending ? (
|
||||
this.renderPending()
|
||||
|
@ -248,11 +248,11 @@ export class Image extends React.Component<Props> {
|
|||
) : null}
|
||||
{bottomOverlay ? (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-image__bottom-overlay',
|
||||
curveBottomLeft ? 'module-image--curved-bottom-left' : null,
|
||||
curveBottomRight ? 'module-image--curved-bottom-right' : null
|
||||
)}
|
||||
className="module-image__bottom-overlay"
|
||||
style={{
|
||||
borderBottomLeftRadius: curveBottomLeft || CurveType.None,
|
||||
borderBottomRightRadius: curveBottomRight || CurveType.None,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{!pending && !imgNotDownloaded && playIconOverlay ? (
|
||||
|
|
|
@ -37,6 +37,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
}),
|
||||
],
|
||||
bottomOverlay: boolean('bottomOverlay', overrideProps.bottomOverlay || false),
|
||||
direction: overrideProps.direction || 'incoming',
|
||||
i18n,
|
||||
isSticker: boolean('isSticker', overrideProps.isSticker || false),
|
||||
onClick: action('onClick'),
|
||||
|
|
|
@ -14,18 +14,23 @@ import {
|
|||
isVideoAttachment,
|
||||
} from '../../types/Attachment';
|
||||
|
||||
import { Image } from './Image';
|
||||
import { Image, CurveType } from './Image';
|
||||
|
||||
import type { LocalizerType, ThemeType } from '../../types/Util';
|
||||
|
||||
export type DirectionType = 'incoming' | 'outgoing';
|
||||
|
||||
export type Props = {
|
||||
attachments: Array<AttachmentType>;
|
||||
withContentAbove?: boolean;
|
||||
withContentBelow?: boolean;
|
||||
bottomOverlay?: boolean;
|
||||
direction: DirectionType;
|
||||
isSticker?: boolean;
|
||||
shouldCollapseAbove?: boolean;
|
||||
shouldCollapseBelow?: boolean;
|
||||
stickerSize?: number;
|
||||
tabIndex?: number;
|
||||
withContentAbove?: boolean;
|
||||
withContentBelow?: boolean;
|
||||
|
||||
i18n: LocalizerType;
|
||||
theme?: ThemeType;
|
||||
|
@ -36,27 +41,85 @@ export type Props = {
|
|||
|
||||
const GAP = 1;
|
||||
|
||||
function getCurves({
|
||||
direction,
|
||||
shouldCollapseAbove,
|
||||
shouldCollapseBelow,
|
||||
withContentAbove,
|
||||
withContentBelow,
|
||||
}: {
|
||||
direction: DirectionType;
|
||||
shouldCollapseAbove?: boolean;
|
||||
shouldCollapseBelow?: boolean;
|
||||
withContentAbove?: boolean;
|
||||
withContentBelow?: boolean;
|
||||
}): {
|
||||
curveTopLeft: CurveType;
|
||||
curveTopRight: CurveType;
|
||||
curveBottomLeft: CurveType;
|
||||
curveBottomRight: CurveType;
|
||||
} {
|
||||
let curveTopLeft = CurveType.None;
|
||||
let curveTopRight = CurveType.None;
|
||||
let curveBottomLeft = CurveType.None;
|
||||
let curveBottomRight = CurveType.None;
|
||||
|
||||
if (shouldCollapseAbove && direction === 'incoming') {
|
||||
curveTopLeft = CurveType.Tiny;
|
||||
curveTopRight = CurveType.Normal;
|
||||
} else if (shouldCollapseAbove && direction === 'outgoing') {
|
||||
curveTopLeft = CurveType.Normal;
|
||||
curveTopRight = CurveType.Tiny;
|
||||
} else if (!withContentAbove) {
|
||||
curveTopLeft = CurveType.Normal;
|
||||
curveTopRight = CurveType.Normal;
|
||||
}
|
||||
|
||||
if (shouldCollapseBelow && direction === 'incoming') {
|
||||
curveBottomLeft = CurveType.Tiny;
|
||||
curveBottomRight = CurveType.None;
|
||||
} else if (shouldCollapseBelow && direction === 'outgoing') {
|
||||
curveBottomLeft = CurveType.None;
|
||||
curveBottomRight = CurveType.Tiny;
|
||||
} else if (!withContentBelow) {
|
||||
curveBottomLeft = CurveType.Normal;
|
||||
curveBottomRight = CurveType.Normal;
|
||||
}
|
||||
|
||||
return {
|
||||
curveTopLeft,
|
||||
curveTopRight,
|
||||
curveBottomLeft,
|
||||
curveBottomRight,
|
||||
};
|
||||
}
|
||||
|
||||
export const ImageGrid = ({
|
||||
attachments,
|
||||
bottomOverlay,
|
||||
direction,
|
||||
i18n,
|
||||
isSticker,
|
||||
stickerSize,
|
||||
onError,
|
||||
onClick,
|
||||
shouldCollapseAbove,
|
||||
shouldCollapseBelow,
|
||||
tabIndex,
|
||||
theme,
|
||||
withContentAbove,
|
||||
withContentBelow,
|
||||
}: Props): JSX.Element | null => {
|
||||
const curveTopLeft = !withContentAbove;
|
||||
const curveTopRight = curveTopLeft;
|
||||
const { curveTopLeft, curveTopRight, curveBottomLeft, curveBottomRight } =
|
||||
getCurves({
|
||||
direction,
|
||||
shouldCollapseAbove,
|
||||
shouldCollapseBelow,
|
||||
withContentAbove,
|
||||
withContentBelow,
|
||||
});
|
||||
|
||||
const curveBottom = !withContentBelow;
|
||||
const curveBottomLeft = curveBottom;
|
||||
const curveBottomRight = curveBottom;
|
||||
|
||||
const withBottomOverlay = Boolean(bottomOverlay && curveBottom);
|
||||
const withBottomOverlay = Boolean(bottomOverlay && !withContentBelow);
|
||||
|
||||
if (!attachments || !attachments.length) {
|
||||
return null;
|
||||
|
|
|
@ -222,15 +222,30 @@ const renderMany = (propsArray: ReadonlyArray<Props>) =>
|
|||
/>
|
||||
));
|
||||
|
||||
const renderBothDirections = (props: Props) =>
|
||||
renderMany([
|
||||
props,
|
||||
{
|
||||
const renderThree = (props: Props) => renderMany([props, props, props]);
|
||||
|
||||
const renderBothDirections = (props: Props) => (
|
||||
<>
|
||||
{renderThree(props)}
|
||||
{renderThree({
|
||||
...props,
|
||||
author: { ...props.author, id: getDefaultConversation().id },
|
||||
direction: 'outgoing',
|
||||
},
|
||||
]);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
const renderSingleBothDirections = (props: Props) => (
|
||||
<>
|
||||
<Message {...props} />
|
||||
<Message
|
||||
{...{
|
||||
...props,
|
||||
author: { ...props.author, id: getDefaultConversation().id },
|
||||
direction: 'outgoing',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
story.add('Plain Message', () => {
|
||||
const props = createProps({
|
||||
|
@ -353,7 +368,7 @@ story.add('Delivered', () => {
|
|||
text: 'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Read', () => {
|
||||
|
@ -363,7 +378,7 @@ story.add('Read', () => {
|
|||
text: 'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Sending', () => {
|
||||
|
@ -373,7 +388,7 @@ story.add('Sending', () => {
|
|||
text: 'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Expiring', () => {
|
||||
|
@ -502,7 +517,7 @@ story.add('Reactions (wider message)', () => {
|
|||
],
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
return renderSingleBothDirections(props);
|
||||
});
|
||||
|
||||
const joyReactions = Array.from({ length: 52 }, () => getJoyReaction());
|
||||
|
@ -577,7 +592,7 @@ story.add('Reactions (short message)', () => {
|
|||
],
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
return renderSingleBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('Avatar in Group', () => {
|
||||
|
@ -588,7 +603,7 @@ story.add('Avatar in Group', () => {
|
|||
text: 'Hello it is me, the saxophone.',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Badge in Group', () => {
|
||||
|
@ -599,7 +614,7 @@ story.add('Badge in Group', () => {
|
|||
text: 'Hello it is me, the saxophone.',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Sticker', () => {
|
||||
|
@ -673,8 +688,8 @@ story.add('Deleted with error', () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Message {...propsPartialError} />
|
||||
<Message {...propsError} />
|
||||
{renderThree(propsPartialError)}
|
||||
{renderThree(propsError)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@ -684,9 +699,10 @@ story.add('Can delete for everyone', () => {
|
|||
status: 'read',
|
||||
text: 'I hope you get this.',
|
||||
canDeleteForEveryone: true,
|
||||
direction: 'outgoing',
|
||||
});
|
||||
|
||||
return <Message {...props} direction="outgoing" />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Error', () => {
|
||||
|
@ -916,7 +932,7 @@ story.add('Link Preview with too new a date', () => {
|
|||
});
|
||||
|
||||
story.add('Image', () => {
|
||||
const props = createProps({
|
||||
const darkImageProps = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
|
@ -928,8 +944,25 @@ story.add('Image', () => {
|
|||
],
|
||||
status: 'sent',
|
||||
});
|
||||
const lightImageProps = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
],
|
||||
status: 'sent',
|
||||
});
|
||||
|
||||
return renderBothDirections(props);
|
||||
return (
|
||||
<>
|
||||
{renderBothDirections(darkImageProps)}
|
||||
{renderBothDirections(lightImageProps)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
for (let i = 2; i <= 5; i += 1) {
|
||||
|
@ -937,39 +970,39 @@ for (let i = 2; i <= 5; i += 1) {
|
|||
const props = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
width: 128,
|
||||
height: 128,
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
width: 128,
|
||||
height: 128,
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
width: 128,
|
||||
height: 128,
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
width: 128,
|
||||
height: 128,
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
fakeAttachment({
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
width: 128,
|
||||
height: 128,
|
||||
url: pngUrl,
|
||||
fileName: 'the-sax.png',
|
||||
contentType: IMAGE_PNG,
|
||||
height: 240,
|
||||
width: 320,
|
||||
}),
|
||||
].slice(0, i),
|
||||
status: 'sent',
|
||||
|
@ -1316,7 +1349,7 @@ story.add('TapToView Error', () => {
|
|||
status: 'sent',
|
||||
});
|
||||
|
||||
return <Message {...props} />;
|
||||
return renderThree(props);
|
||||
});
|
||||
|
||||
story.add('Dangerous File Type', () => {
|
||||
|
@ -1419,23 +1452,23 @@ story.add('Not approved, with link preview', () => {
|
|||
|
||||
story.add('Custom Color', () => (
|
||||
<>
|
||||
<Message
|
||||
{...createProps({ text: 'Solid.' })}
|
||||
direction="outgoing"
|
||||
customColor={{
|
||||
{renderThree({
|
||||
...createProps({ text: 'Solid.' }),
|
||||
direction: 'outgoing',
|
||||
customColor: {
|
||||
start: { hue: 82, saturation: 35 },
|
||||
}}
|
||||
/>
|
||||
},
|
||||
})}
|
||||
<br style={{ clear: 'both' }} />
|
||||
<Message
|
||||
{...createProps({ text: 'Gradient.' })}
|
||||
direction="outgoing"
|
||||
customColor={{
|
||||
{renderThree({
|
||||
...createProps({ text: 'Gradient.' }),
|
||||
direction: 'outgoing',
|
||||
customColor: {
|
||||
deg: 192,
|
||||
start: { hue: 304, saturation: 85 },
|
||||
end: { hue: 231, saturation: 76 },
|
||||
}}
|
||||
/>
|
||||
},
|
||||
})}
|
||||
</>
|
||||
));
|
||||
|
||||
|
@ -1506,20 +1539,18 @@ story.add('Collapsing text-only group messages', () => {
|
|||
story.add('Story reply', () => {
|
||||
const conversation = getDefaultConversation();
|
||||
|
||||
return (
|
||||
<Message
|
||||
{...createProps({ text: 'Wow!' })}
|
||||
storyReplyContext={{
|
||||
authorTitle: conversation.title,
|
||||
conversationColor: ConversationColors[0],
|
||||
isFromMe: false,
|
||||
rawAttachment: fakeAttachment({
|
||||
url: '/fixtures/snow.jpg',
|
||||
thumbnail: fakeThumbnail('/fixtures/snow.jpg'),
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return renderThree({
|
||||
...createProps({ text: 'Wow!' }),
|
||||
storyReplyContext: {
|
||||
authorTitle: conversation.title,
|
||||
conversationColor: ConversationColors[0],
|
||||
isFromMe: false,
|
||||
rawAttachment: fakeAttachment({
|
||||
url: '/fixtures/snow.jpg',
|
||||
thumbnail: fakeThumbnail('/fixtures/snow.jpg'),
|
||||
}),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const fullContact = {
|
||||
|
@ -1559,7 +1590,7 @@ story.add('EmbeddedContact: Full Contact', () => {
|
|||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: 2x Incoming, with Send Message', () => {
|
||||
story.add('EmbeddedContact: with Send Message', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
...fullContact,
|
||||
|
@ -1568,19 +1599,7 @@ story.add('EmbeddedContact: 2x Incoming, with Send Message', () => {
|
|||
},
|
||||
direction: 'incoming',
|
||||
});
|
||||
return renderMany([props, props]);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: 2x Outgoing, with Send Message', () => {
|
||||
const props = createProps({
|
||||
contact: {
|
||||
...fullContact,
|
||||
firstNumber: fullContact.number[0].value,
|
||||
uuid: UUID.generate().toString(),
|
||||
},
|
||||
direction: 'outgoing',
|
||||
});
|
||||
return renderMany([props, props]);
|
||||
return renderBothDirections(props);
|
||||
});
|
||||
|
||||
story.add('EmbeddedContact: Only Email', () => {
|
||||
|
|
|
@ -28,7 +28,7 @@ import { MessageMetadata } from './MessageMetadata';
|
|||
import { MessageTextMetadataSpacer } from './MessageTextMetadataSpacer';
|
||||
import { ImageGrid } from './ImageGrid';
|
||||
import { GIF } from './GIF';
|
||||
import { Image } from './Image';
|
||||
import { CurveType, Image } from './Image';
|
||||
import { ContactName } from './ContactName';
|
||||
import type { QuotedAttachmentType } from './Quote';
|
||||
import { Quote } from './Quote';
|
||||
|
@ -908,18 +908,17 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
<div className={containerClassName}>
|
||||
<ImageGrid
|
||||
attachments={attachments}
|
||||
withContentAbove={
|
||||
isSticker || withContentAbove || shouldCollapseAbove
|
||||
}
|
||||
withContentBelow={
|
||||
isSticker || withContentBelow || shouldCollapseBelow
|
||||
}
|
||||
direction={direction}
|
||||
withContentAbove={isSticker || withContentAbove}
|
||||
withContentBelow={isSticker || withContentBelow}
|
||||
isSticker={isSticker}
|
||||
stickerSize={STICKER_SIZE}
|
||||
bottomOverlay={bottomOverlay}
|
||||
i18n={i18n}
|
||||
theme={theme}
|
||||
onError={this.handleImageError}
|
||||
theme={theme}
|
||||
shouldCollapseAbove={shouldCollapseAbove}
|
||||
shouldCollapseBelow={shouldCollapseBelow}
|
||||
tabIndex={tabIndex}
|
||||
onClick={attachment => {
|
||||
if (!isDownloaded(attachment)) {
|
||||
|
@ -1060,6 +1059,7 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
openLink,
|
||||
previews,
|
||||
quote,
|
||||
shouldCollapseAbove,
|
||||
theme,
|
||||
kickOffAttachmentDownload,
|
||||
} = this.props;
|
||||
|
@ -1113,6 +1113,8 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
<ImageGrid
|
||||
attachments={[first.image]}
|
||||
withContentAbove={withContentAbove}
|
||||
direction={direction}
|
||||
shouldCollapseAbove={shouldCollapseAbove}
|
||||
withContentBelow
|
||||
onError={this.handleImageError}
|
||||
i18n={i18n}
|
||||
|
@ -1124,10 +1126,14 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
{first.image && previewHasImage && !isFullSizeImage ? (
|
||||
<div className="module-message__link-preview__icon_container">
|
||||
<Image
|
||||
smallCurveTopLeft={!withContentAbove}
|
||||
noBorder
|
||||
noBackground
|
||||
softCorners
|
||||
curveBottomLeft={
|
||||
withContentAbove ? CurveType.Tiny : CurveType.Small
|
||||
}
|
||||
curveBottomRight={CurveType.Tiny}
|
||||
curveTopRight={CurveType.Tiny}
|
||||
curveTopLeft={CurveType.Tiny}
|
||||
alt={i18n('previewThumbnail', [first.domain])}
|
||||
height={72}
|
||||
width={72}
|
||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||
import classNames from 'classnames';
|
||||
import { unescape } from 'lodash';
|
||||
|
||||
import { Image } from './Image';
|
||||
import { CurveType, Image } from './Image';
|
||||
import { LinkPreviewDate } from './LinkPreviewDate';
|
||||
|
||||
import type { AttachmentType } from '../../types/Attachment';
|
||||
|
@ -51,7 +51,10 @@ export const StagedLinkPreview: React.FC<Props> = ({
|
|||
<div className="module-staged-link-preview__icon-container">
|
||||
<Image
|
||||
alt={i18n('stagedPreviewThumbnail', [domain])}
|
||||
softCorners
|
||||
curveBottomLeft={CurveType.Tiny}
|
||||
curveBottomRight={CurveType.Tiny}
|
||||
curveTopRight={CurveType.Tiny}
|
||||
curveTopLeft={CurveType.Tiny}
|
||||
height={72}
|
||||
width={72}
|
||||
url={image.url}
|
||||
|
|
Loading…
Reference in a new issue