Full width/height stories

This commit is contained in:
Josh Perez 2022-04-22 14:36:34 -04:00 committed by GitHub
parent 3a1df01c9e
commit 4602cef6da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 163 additions and 88 deletions

View File

@ -3,7 +3,6 @@
.StoryImage {
align-items: center;
border-radius: 8px;
display: flex;
height: 100%;
justify-content: center;

View File

@ -3,8 +3,7 @@
.StoryViewer {
&__overlay {
background: $color-gray-95;
filter: blur(160px);
background-size: contain;
height: 100vh;
left: 0;
position: absolute;
@ -15,6 +14,8 @@
&__content {
align-items: center;
backdrop-filter: blur(90px);
background: $color-black-alpha-20;
display: flex;
flex-direction: column;
height: 100vh;
@ -29,16 +30,19 @@
&__close-button {
@include button-reset;
@include modal-close-button;
right: 28px;
top: var(--title-bar-drag-area-height);
z-index: $z-index-above-base;
}
&__more {
@include button-reset;
height: 24px;
position: absolute;
right: 48px;
right: 80px;
top: var(--title-bar-drag-area-height);
width: 24px;
z-index: $z-index-above-base;
@include color-svg('../images/icons/v2/more-horiz-24.svg', $color-white);
@ -51,14 +55,12 @@
&__container {
flex-grow: 1;
margin-top: 36px;
overflow: hidden;
position: relative;
z-index: $z-index-base;
}
&__story {
border-radius: 12px;
max-height: 100%;
outline: none;
width: auto;
@ -67,7 +69,7 @@
&__meta {
bottom: 0;
left: 50%;
padding: 16px;
padding: 0 16px;
position: absolute;
transform: translateX(-50%);
width: 284px;
@ -94,8 +96,10 @@
@include font-body-1-bold;
color: $color-gray-05;
padding: 4px 0;
margin-bottom: 24px;
&__overlay {
@include button-reset;
background: $color-black-alpha-60;
height: 100%;
left: 0;
@ -107,11 +111,9 @@
}
&__actions {
align-items: center;
display: flex;
justify-content: center;
margin-bottom: 32px;
min-height: 52px;
min-height: 60px;
}
&__reply {

View File

@ -122,3 +122,38 @@ story.add('So many stories', () => {
/>
);
});
story.add('Caption', () => (
<StoryViewer
{...getDefaultProps()}
stories={[
{
attachment: fakeAttachment({
caption: 'This place looks lovely',
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
}),
messageId: '123',
sender: getDefaultConversation(),
timestamp: Date.now(),
},
]}
/>
));
story.add('Long Caption', () => (
<StoryViewer
{...getDefaultProps()}
stories={[
{
attachment: fakeAttachment({
caption:
'Snowycle, snowycle, snowycle\nI want to ride my snowycle, snowycle, snowycle\nI want to ride my snowycle\nI want to ride my snow\nI want to ride my snowycle\nI want to ride it where I like\nSnowycle, snowycle, snowycle\nI want to ride my snowycle, snowycle, snowycle\nI want to ride my snowycle\nI want to ride my snow\nI want to ride my snowycle\nI want to ride it where I like\nSnowycle, snowycle, snowycle\nI want to ride my snowycle, snowycle, snowycle\nI want to ride my snowycle\nI want to ride my snow\nI want to ride my snowycle\nI want to ride it where I like',
url: '/fixtures/snow.jpg',
}),
messageId: '123',
sender: getDefaultConversation(),
timestamp: Date.now(),
},
]}
/>
));

View File

@ -17,6 +17,7 @@ import { MessageTimestamp } from './conversation/MessageTimestamp';
import { StoryImage } from './StoryImage';
import { StoryViewsNRepliesModal } from './StoryViewsNRepliesModal';
import { getAvatarColor } from '../types/Colors';
import { getStoryBackground } from '../util/getStoryBackground';
import { getStoryDuration } from '../util/getStoryDuration';
import { graphemeAwareSlice } from '../util/graphemeAwareSlice';
import { isDownloaded, isDownloading } from '../types/Attachment';
@ -209,12 +210,12 @@ export const StoryViewer = ({
}, [currentStoryIndex, spring, storyDuration]);
useEffect(() => {
if (hasReplyModal) {
if (hasReplyModal || hasExpandedCaption) {
spring.pause();
} else {
spring.resume();
}
}, [hasReplyModal, spring]);
}, [hasExpandedCaption, hasReplyModal, spring]);
useEffect(() => {
markStoryRead(messageId);
@ -273,21 +274,11 @@ export const StoryViewer = ({
return (
<FocusTrap focusTrapOptions={{ allowOutsideClick: true }}>
<div className="StoryViewer">
<div className="StoryViewer__overlay" />
<div
className="StoryViewer__overlay"
style={{ background: getStoryBackground(attachment) }}
/>
<div className="StoryViewer__content">
<button
aria-label={i18n('MyStories__more')}
className="StoryViewer__more"
tabIndex={0}
type="button"
/>
<button
aria-label={i18n('close')}
className="StoryViewer__close-button"
onClick={onClose}
tabIndex={0}
type="button"
/>
<div className="StoryViewer__container">
<StoryImage
attachment={attachment}
@ -298,7 +289,12 @@ export const StoryViewer = ({
storyId={messageId}
/>
{hasExpandedCaption && (
<div className="StoryViewer__caption__overlay" />
<button
aria-label={i18n('close-popup')}
className="StoryViewer__caption__overlay"
onClick={() => setHasExpandedCaption(false)}
type="button"
/>
)}
<div className="StoryViewer__meta">
{caption && (
@ -391,54 +387,67 @@ export const StoryViewer = ({
</div>
))}
</div>
<div className="StoryViewer__actions">
{isMe ? (
<>
{viewCount &&
(viewCount === 1 ? (
<Intl
i18n={i18n}
id="MyStories__views--singular"
components={[<strong>{viewCount}</strong>]}
/>
) : (
<Intl
i18n={i18n}
id="MyStories__views--plural"
components={[<strong>{viewCount}</strong>]}
/>
))}
{viewCount && replyCount && ' '}
{replyCount &&
(replyCount === 1 ? (
<Intl
i18n={i18n}
id="MyStories__replies--singular"
components={[<strong>{replyCount}</strong>]}
/>
) : (
<Intl
i18n={i18n}
id="MyStories__replies--plural"
components={[<strong>{replyCount}</strong>]}
/>
))}
</>
) : (
canReply && (
<button
className="StoryViewer__reply"
onClick={() => setHasReplyModal(true)}
tabIndex={0}
type="button"
>
{i18n('StoryViewer__reply')}
</button>
)
)}
</div>
</div>
</div>
<div className="StoryViewer__actions">
{isMe ? (
<>
{viewCount &&
(viewCount === 1 ? (
<Intl
i18n={i18n}
id="MyStories__views--singular"
components={[<strong>{viewCount}</strong>]}
/>
) : (
<Intl
i18n={i18n}
id="MyStories__views--plural"
components={[<strong>{viewCount}</strong>]}
/>
))}
{viewCount && replyCount && ' '}
{replyCount &&
(replyCount === 1 ? (
<Intl
i18n={i18n}
id="MyStories__replies--singular"
components={[<strong>{replyCount}</strong>]}
/>
) : (
<Intl
i18n={i18n}
id="MyStories__replies--plural"
components={[<strong>{replyCount}</strong>]}
/>
))}
</>
) : (
canReply && (
<button
className="StoryViewer__reply"
onClick={() => setHasReplyModal(true)}
tabIndex={0}
type="button"
>
{i18n('StoryViewer__reply')}
</button>
)
)}
</div>
<button
aria-label={i18n('MyStories__more')}
className="StoryViewer__more"
tabIndex={0}
type="button"
/>
<button
aria-label={i18n('close')}
className="StoryViewer__close-button"
onClick={onClose}
tabIndex={0}
type="button"
/>
</div>
{hasReplyModal && canReply && (
<StoryViewsNRepliesModal

View File

@ -13,6 +13,10 @@ import { TextAttachmentStyleType } from '../types/Attachment';
import { count } from '../util/grapheme';
import { getDomain } from '../types/LinkPreview';
import { getFontNameByTextScript } from '../util/getFontNameByTextScript';
import {
getHexFromNumber,
getBackgroundColor,
} from '../util/getStoryBackground';
const renderNewLines: RenderTextCallbackType = ({
text: textWithNewLines,
@ -53,20 +57,6 @@ function getTextSize(text: string): TextSize {
return TextSize.Small;
}
function getHexFromNumber(color: number): string {
return `#${color.toString(16).slice(2)}`;
}
function getBackground({ color, gradient }: TextAttachmentType): string {
if (gradient) {
return `linear-gradient(${gradient.angle}deg, ${getHexFromNumber(
gradient.startColor || COLOR_WHITE_INT
)}, ${getHexFromNumber(gradient.endColor || COLOR_WHITE_INT)})`;
}
return getHexFromNumber(color || COLOR_WHITE_INT);
}
function getFont(
text: string,
textSize: TextSize,
@ -123,7 +113,7 @@ export const TextAttachment = ({
<div
className="TextAttachment__story"
style={{
background: getBackground(textAttachment),
background: getBackgroundColor(textAttachment),
transform: `scale(${(contentRect.bounds?.height || 1) / 1280})`,
}}
>

View File

@ -0,0 +1,40 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { AttachmentType, TextAttachmentType } from '../types/Attachment';
const COLOR_BLACK_ALPHA_90 = 'rgba(0, 0, 0, 0.9)';
const COLOR_WHITE_INT = 4294704123;
export function getHexFromNumber(color: number): string {
return `#${color.toString(16).slice(2)}`;
}
export function getBackgroundColor({
color,
gradient,
}: TextAttachmentType): string {
if (gradient) {
return `linear-gradient(${gradient.angle}deg, ${getHexFromNumber(
gradient.startColor || COLOR_WHITE_INT
)}, ${getHexFromNumber(gradient.endColor || COLOR_WHITE_INT)})`;
}
return getHexFromNumber(color || COLOR_WHITE_INT);
}
export function getStoryBackground(attachment?: AttachmentType): string {
if (!attachment) {
return COLOR_BLACK_ALPHA_90;
}
if (attachment.textAttachment) {
return getBackgroundColor(attachment.textAttachment);
}
if (attachment.url) {
return `url("${attachment.url}")`;
}
return COLOR_BLACK_ALPHA_90;
}