Story viewing improvements
This commit is contained in:
parent
d4e0f6a38d
commit
7d8464757b
4 changed files with 149 additions and 2 deletions
|
@ -40,6 +40,7 @@ $color-black-alpha-05: rgba($color-black, 0.05);
|
||||||
$color-black-alpha-06: rgba($color-black, 0.06);
|
$color-black-alpha-06: rgba($color-black, 0.06);
|
||||||
$color-black-alpha-08: rgba($color-black, 0.08);
|
$color-black-alpha-08: rgba($color-black, 0.08);
|
||||||
$color-black-alpha-12: rgba($color-black, 0.12);
|
$color-black-alpha-12: rgba($color-black, 0.12);
|
||||||
|
$color-black-alpha-16: rgba($color-black, 0.16);
|
||||||
$color-black-alpha-20: rgba($color-black, 0.2);
|
$color-black-alpha-20: rgba($color-black, 0.2);
|
||||||
$color-black-alpha-30: rgba($color-black, 0.3);
|
$color-black-alpha-30: rgba($color-black, 0.3);
|
||||||
$color-black-alpha-40: rgba($color-black, 0.4);
|
$color-black-alpha-40: rgba($color-black, 0.4);
|
||||||
|
@ -49,6 +50,8 @@ $color-black-alpha-70: rgba($color-black, 0.7);
|
||||||
$color-black-alpha-80: rgba($color-black, 0.8);
|
$color-black-alpha-80: rgba($color-black, 0.8);
|
||||||
$color-black-alpha-90: rgba($color-black, 0.9);
|
$color-black-alpha-90: rgba($color-black, 0.9);
|
||||||
|
|
||||||
|
$color-transparent: rgba(0, 0, 0, 0);
|
||||||
|
|
||||||
$color-ultramarine-dark: #1851b4;
|
$color-ultramarine-dark: #1851b4;
|
||||||
$color-ultramarine-icon: #3a76f0;
|
$color-ultramarine-icon: #3a76f0;
|
||||||
$color-ultramarine-light: #6191f3;
|
$color-ultramarine-light: #6191f3;
|
||||||
|
|
|
@ -72,7 +72,8 @@
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 284px;
|
min-width: 284px;
|
||||||
|
width: 56.25vh;
|
||||||
z-index: $z-index-above-base;
|
z-index: $z-index-above-base;
|
||||||
|
|
||||||
&--group-avatar {
|
&--group-avatar {
|
||||||
|
@ -93,7 +94,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__caption {
|
&__caption {
|
||||||
@include font-body-1-bold;
|
@include font-body-1;
|
||||||
color: $color-gray-05;
|
color: $color-gray-05;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
@ -146,4 +147,69 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__arrow {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
position: absolute;
|
||||||
|
width: 25%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include button-reset;
|
||||||
|
height: 24px;
|
||||||
|
opacity: 0;
|
||||||
|
width: 24px;
|
||||||
|
transition: opacity 200ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 24px;
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/chevron-left-24.svg',
|
||||||
|
$color-white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 24px;
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/chevron-right-24.svg',
|
||||||
|
$color-white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--visible button {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__protection {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
z-index: $z-index-above-base;
|
||||||
|
|
||||||
|
&--top {
|
||||||
|
background: linear-gradient($color-black-alpha-16, $color-transparent);
|
||||||
|
top: 0;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bottom {
|
||||||
|
background: linear-gradient($color-transparent, $color-black-alpha-40);
|
||||||
|
bottom: 0;
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ function getDefaultProps(): PropsType {
|
||||||
stories: [
|
stories: [
|
||||||
{
|
{
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
|
path: 'snow.jpg',
|
||||||
url: '/fixtures/snow.jpg',
|
url: '/fixtures/snow.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
|
@ -60,6 +61,7 @@ story.add('Wide story', () => (
|
||||||
stories={[
|
stories={[
|
||||||
{
|
{
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
|
path: 'file.jpg',
|
||||||
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
|
@ -89,6 +91,7 @@ story.add('Multi story', () => {
|
||||||
stories={[
|
stories={[
|
||||||
{
|
{
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
|
path: 'snow.jpg',
|
||||||
url: '/fixtures/snow.jpg',
|
url: '/fixtures/snow.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
|
@ -97,6 +100,7 @@ story.add('Multi story', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
|
path: 'file.jpg',
|
||||||
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '456',
|
messageId: '456',
|
||||||
|
@ -115,6 +119,7 @@ story.add('Caption', () => (
|
||||||
{
|
{
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
caption: 'This place looks lovely',
|
caption: 'This place looks lovely',
|
||||||
|
path: 'file.jpg',
|
||||||
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
url: '/fixtures/nathan-anderson-316188-unsplash.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
|
@ -133,6 +138,7 @@ story.add('Long Caption', () => (
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
caption:
|
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',
|
'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',
|
||||||
|
path: 'file.jpg',
|
||||||
url: '/fixtures/snow.jpg',
|
url: '/fixtures/snow.jpg',
|
||||||
}),
|
}),
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
|
|
|
@ -9,6 +9,7 @@ import React, {
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { useSpring, animated, to } from '@react-spring/web';
|
import { useSpring, animated, to } from '@react-spring/web';
|
||||||
import type { BodyRangeType, LocalizerType } from '../types/Util';
|
import type { BodyRangeType, LocalizerType } from '../types/Util';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
|
@ -76,6 +77,13 @@ export type PropsType = {
|
||||||
const CAPTION_BUFFER = 20;
|
const CAPTION_BUFFER = 20;
|
||||||
const CAPTION_INITIAL_LENGTH = 200;
|
const CAPTION_INITIAL_LENGTH = 200;
|
||||||
const CAPTION_MAX_LENGTH = 700;
|
const CAPTION_MAX_LENGTH = 700;
|
||||||
|
const MOUSE_IDLE_TIME = 3000;
|
||||||
|
|
||||||
|
enum Arrow {
|
||||||
|
None,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
export const StoryViewer = ({
|
export const StoryViewer = ({
|
||||||
conversationId,
|
conversationId,
|
||||||
|
@ -313,6 +321,38 @@ export const StoryViewer = ({
|
||||||
loadStoryReplies(conversationId, messageId);
|
loadStoryReplies(conversationId, messageId);
|
||||||
}, [conversationId, isGroupStory, loadStoryReplies, messageId]);
|
}, [conversationId, isGroupStory, loadStoryReplies, messageId]);
|
||||||
|
|
||||||
|
const [arrowToShow, setArrowToShow] = useState<Arrow>(Arrow.None);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (arrowToShow === Arrow.None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastMouseMove: number | undefined;
|
||||||
|
|
||||||
|
function updateLastMouseMove() {
|
||||||
|
lastMouseMove = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMouseIdle() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (lastMouseMove && Date.now() - lastMouseMove > MOUSE_IDLE_TIME) {
|
||||||
|
setArrowToShow(Arrow.None);
|
||||||
|
} else {
|
||||||
|
checkMouseIdle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkMouseIdle();
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', updateLastMouseMove);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
lastMouseMove = undefined;
|
||||||
|
document.removeEventListener('mousemove', updateLastMouseMove);
|
||||||
|
};
|
||||||
|
}, [arrowToShow]);
|
||||||
|
|
||||||
const replies =
|
const replies =
|
||||||
replyState && replyState.messageId === messageId ? replyState.replies : [];
|
replyState && replyState.messageId === messageId ? replyState.replies : [];
|
||||||
|
|
||||||
|
@ -327,6 +367,22 @@ export const StoryViewer = ({
|
||||||
style={{ background: getStoryBackground(attachment) }}
|
style={{ background: getStoryBackground(attachment) }}
|
||||||
/>
|
/>
|
||||||
<div className="StoryViewer__content">
|
<div className="StoryViewer__content">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'StoryViewer__arrow StoryViewer__arrow--left',
|
||||||
|
{
|
||||||
|
'StoryViewer__arrow--visible': arrowToShow === Arrow.Left,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
onMouseMove={() => setArrowToShow(Arrow.Left)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label={i18n('back')}
|
||||||
|
onClick={showPrevStory}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="StoryViewer__protection StoryViewer__protection--top" />
|
||||||
<div className="StoryViewer__container">
|
<div className="StoryViewer__container">
|
||||||
<StoryImage
|
<StoryImage
|
||||||
attachment={attachment}
|
attachment={attachment}
|
||||||
|
@ -481,6 +537,22 @@ export const StoryViewer = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'StoryViewer__arrow StoryViewer__arrow--right',
|
||||||
|
{
|
||||||
|
'StoryViewer__arrow--visible': arrowToShow === Arrow.Right,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
onMouseMove={() => setArrowToShow(Arrow.Right)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label={i18n('forward')}
|
||||||
|
onClick={showNextStory}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="StoryViewer__protection StoryViewer__protection--bottom" />
|
||||||
<button
|
<button
|
||||||
aria-label={i18n('MyStories__more')}
|
aria-label={i18n('MyStories__more')}
|
||||||
className="StoryViewer__more"
|
className="StoryViewer__more"
|
||||||
|
|
Loading…
Reference in a new issue