Create text stories

This commit is contained in:
Josh Perez 2022-06-16 20:48:57 -04:00 committed by GitHub
parent 973b2264fe
commit d970d427f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 2433 additions and 1106 deletions

View file

@ -1192,7 +1192,10 @@ export class Message extends React.PureComponent<Props, State> {
/>
) : null}
<div className="module-message__link-preview__content">
{first.image && previewHasImage && !isFullSizeImage ? (
{first.image &&
first.domain &&
previewHasImage &&
!isFullSizeImage ? (
<div className="module-message__link-preview__icon_container">
<Image
noBorder

View file

@ -1,16 +1,16 @@
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Meta, Story } from '@storybook/react';
import * as React from 'react';
import { date, text } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import type { AttachmentType } from '../../types/Attachment';
import { stringToMIMEType } from '../../types/MIME';
import { setupI18n } from '../../util/setupI18n';
import enMessages from '../../../_locales/en/messages.json';
import type { Props } from './StagedLinkPreview';
import enMessages from '../../../_locales/en/messages.json';
import { StagedLinkPreview } from './StagedLinkPreview';
import { fakeAttachment } from '../../test-both/helpers/fakeAttachment';
import { setupI18n } from '../../util/setupI18n';
import { IMAGE_JPEG } from '../../types/MIME';
const LONG_TITLE =
"This is a super-sweet site. And it's got some really amazing content in store for you if you just click that link. Can you click that link for me?";
@ -21,150 +21,109 @@ const i18n = setupI18n('en', enMessages);
export default {
title: 'Components/Conversation/StagedLinkPreview',
};
component: StagedLinkPreview,
} as Meta;
const createAttachment = (
props: Partial<AttachmentType> = {}
): AttachmentType => ({
contentType: stringToMIMEType(
text('attachment contentType', props.contentType || '')
),
fileName: text('attachment fileName', props.fileName || ''),
url: text('attachment url', props.url || ''),
size: 24325,
});
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
title: text(
'title',
typeof overrideProps.title === 'string'
? overrideProps.title
: 'This is a super-sweet site'
),
description: text(
'description',
typeof overrideProps.description === 'string'
? overrideProps.description
: 'This is a description'
),
date: date('date', new Date(overrideProps.date || 0)),
domain: text('domain', overrideProps.domain || 'signal.org'),
image: overrideProps.image,
const getDefaultProps = (): Props => ({
date: Date.now(),
description: 'This is a description',
domain: 'signal.org',
i18n,
onClose: action('onClose'),
title: 'This is a super-sweet site',
url: 'https://www.signal.org',
});
export const Loading = (): JSX.Element => {
const props = createProps({ domain: '' });
const Template: Story<Props> = args => <StagedLinkPreview {...args} />;
return <StagedLinkPreview {...props} />;
export const Loading = Template.bind({});
Loading.args = {
...getDefaultProps(),
domain: '',
};
export const NoImage = (): JSX.Element => {
return <StagedLinkPreview {...createProps()} />;
export const NoImage = Template.bind({});
export const Image = Template.bind({});
Image.args = {
...getDefaultProps(),
image: fakeAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: IMAGE_JPEG,
}),
};
export const Image = (): JSX.Element => {
const props = createProps({
image: createAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: stringToMIMEType('image/jpeg'),
}),
});
return <StagedLinkPreview {...props} />;
export const ImageNoTitleOrDescription = Template.bind({});
ImageNoTitleOrDescription.args = {
...getDefaultProps(),
title: '',
description: '',
domain: 'instagram.com',
image: fakeAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: IMAGE_JPEG,
}),
};
export const ImageNoTitleOrDescription = (): JSX.Element => {
const props = createProps({
title: '',
description: '',
domain: 'instagram.com',
image: createAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: stringToMIMEType('image/jpeg'),
}),
});
return <StagedLinkPreview {...props} />;
};
ImageNoTitleOrDescription.story = {
name: 'Image, No Title Or Description',
};
export const NoImageLongTitleWithDescription = (): JSX.Element => {
const props = createProps({
title: LONG_TITLE,
});
return <StagedLinkPreview {...props} />;
export const NoImageLongTitleWithDescription = Template.bind({});
NoImageLongTitleWithDescription.args = {
...getDefaultProps(),
title: LONG_TITLE,
};
NoImageLongTitleWithDescription.story = {
name: 'No Image, Long Title With Description',
};
export const NoImageLongTitleWithoutDescription = (): JSX.Element => {
const props = createProps({
title: LONG_TITLE,
description: '',
});
return <StagedLinkPreview {...props} />;
export const NoImageLongTitleWithoutDescription = Template.bind({});
NoImageLongTitleWithoutDescription.args = {
...getDefaultProps(),
title: LONG_TITLE,
description: '',
};
NoImageLongTitleWithoutDescription.story = {
name: 'No Image, Long Title Without Description',
};
export const ImageLongTitleWithoutDescription = (): JSX.Element => {
const props = createProps({
title: LONG_TITLE,
image: createAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: stringToMIMEType('image/jpeg'),
}),
});
return <StagedLinkPreview {...props} />;
export const ImageLongTitleWithoutDescription = Template.bind({});
ImageLongTitleWithoutDescription.args = {
...getDefaultProps(),
title: LONG_TITLE,
image: fakeAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: IMAGE_JPEG,
}),
};
ImageLongTitleWithoutDescription.story = {
name: 'Image, Long Title Without Description',
};
export const ImageLongTitleAndDescription = (): JSX.Element => {
const props = createProps({
title: LONG_TITLE,
description: LONG_DESCRIPTION,
image: createAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: stringToMIMEType('image/jpeg'),
}),
});
return <StagedLinkPreview {...props} />;
export const ImageLongTitleAndDescription = Template.bind({});
ImageLongTitleAndDescription.args = {
...getDefaultProps(),
title: LONG_TITLE,
description: LONG_DESCRIPTION,
image: fakeAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: IMAGE_JPEG,
}),
};
ImageLongTitleAndDescription.story = {
name: 'Image, Long Title And Description',
};
export const EverythingImageTitleDescriptionAndDate = (): JSX.Element => {
const props = createProps({
title: LONG_TITLE,
description: LONG_DESCRIPTION,
date: Date.now(),
image: createAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: stringToMIMEType('image/jpeg'),
}),
});
return <StagedLinkPreview {...props} />;
export const EverythingImageTitleDescriptionAndDate = Template.bind({});
EverythingImageTitleDescriptionAndDate.args = {
...getDefaultProps(),
title: LONG_TITLE,
description: LONG_DESCRIPTION,
image: fakeAttachment({
url: '/fixtures/kitten-4-112-112.jpg',
contentType: IMAGE_JPEG,
}),
};
EverythingImageTitleDescriptionAndDate.story = {
name: 'Everything: image, title, description, and date',
};

View file

@ -8,84 +8,86 @@ import { unescape } from 'lodash';
import { CurveType, Image } from './Image';
import { LinkPreviewDate } from './LinkPreviewDate';
import type { AttachmentType } from '../../types/Attachment';
import { isImageAttachment } from '../../types/Attachment';
import type { LinkPreviewType } from '../../types/message/LinkPreviews';
import type { LocalizerType } from '../../types/Util';
import { getClassNamesFor } from '../../util/getClassNamesFor';
import { isImageAttachment } from '../../types/Attachment';
export type Props = {
title?: string;
description?: null | string;
date?: null | number;
domain?: string;
image?: AttachmentType;
export type Props = LinkPreviewType & {
i18n: LocalizerType;
moduleClassName?: string;
onClose?: () => void;
};
export const StagedLinkPreview: React.FC<Props> = ({
onClose,
i18n,
title,
description,
image,
date,
description,
domain,
i18n,
image,
moduleClassName,
onClose,
title,
}: Props) => {
const isImage = isImageAttachment(image);
const isLoaded = Boolean(domain);
const getClassName = getClassNamesFor(
'module-staged-link-preview',
moduleClassName
);
return (
<div
className={classNames(
'module-staged-link-preview',
!isLoaded ? 'module-staged-link-preview--is-loading' : null
getClassName(''),
!isLoaded ? getClassName('--is-loading') : null
)}
>
{!isLoaded ? (
<div className="module-staged-link-preview__loading">
<div className={getClassName('__loading')}>
{i18n('loadingPreview')}
</div>
) : null}
{isLoaded && image && isImage && domain ? (
<div className="module-staged-link-preview__icon-container">
<div className={getClassName('__icon-container')}>
<Image
alt={i18n('stagedPreviewThumbnail', [domain])}
attachment={image}
curveBottomLeft={CurveType.Tiny}
curveBottomRight={CurveType.Tiny}
curveTopRight={CurveType.Tiny}
curveTopLeft={CurveType.Tiny}
curveTopRight={CurveType.Tiny}
height={72}
width={72}
url={image.url}
attachment={image}
i18n={i18n}
url={image.url}
width={72}
/>
</div>
) : null}
{isLoaded && !image && <div className={getClassName('__no-image')} />}
{isLoaded ? (
<div className="module-staged-link-preview__content">
<div className="module-staged-link-preview__title">{title}</div>
<div className={getClassName('__content')}>
<div className={getClassName('__title')}>{title}</div>
{description && (
<div className="module-staged-link-preview__description">
<div className={getClassName('__description')}>
{unescape(description)}
</div>
)}
<div className="module-staged-link-preview__footer">
<div className="module-staged-link-preview__location">{domain}</div>
<LinkPreviewDate
date={date}
className="module-message__link-preview__date"
/>
<div className={getClassName('__footer')}>
<div className={getClassName('__location')}>{domain}</div>
<LinkPreviewDate date={date} className={getClassName('__date')} />
</div>
</div>
) : null}
<button
type="button"
className="module-staged-link-preview__close-button"
onClick={onClose}
aria-label={i18n('close')}
/>
{onClose && (
<button
aria-label={i18n('close')}
className={getClassName('__close-button')}
onClick={onClose}
type="button"
/>
)}
</div>
);
};