feat: updated panel buttons

add params to panel state to be used in future, not tested yet
pull/3017/head
William Grant 1 year ago
parent 537897dedb
commit 22b0ab5f2f

@ -602,12 +602,6 @@ input {
}
}
.module-message-detail {
.module-message {
pointer-events: none;
}
}
.module-message__text {
white-space: pre-wrap;
}

@ -18,15 +18,16 @@
}
}
// TODO move this into the right panel as Styled container component
.conversation-item__options-pane {
position: absolute;
height: 100%;
height: var(--right-panel-height);
right: 0vw;
transition: transform 0.3s ease-in-out;
transform: translateX(100%);
will-change: transform;
width: 25vw;
width: var(--right-panel-width);
z-index: 5;
background-color: var(--background-primary-color);
@ -91,6 +92,11 @@
flex-direction: column;
position: relative;
outline: none;
height: inherit;
&-left {
flex-grow: 1;
}
.conversation-messages {
display: flex;
@ -104,24 +110,6 @@
background-color: var(--background-secondary-color);
border-top: 1px solid var(--border-color);
}
.conversation-info-panel {
position: absolute;
justify-content: flex-start;
flex-direction: column;
align-items: center;
height: 100%;
width: 100%;
z-index: 5; // to be sure to hide the borders of images in messages
background-color: inherit;
display: none;
padding: 20px;
&.show {
display: flex;
background: var(--background-primary-color);
}
}
}
.composition-container {

@ -1,106 +1,4 @@
.right-panel {
display: flex;
flex-direction: column;
height: 100%;
width: -webkit-fill-available;
align-items: center;
&-header {
margin-top: var(--margins-lg);
margin-inline-start: var(--margins-sm);
margin-inline-end: var(--margins-sm);
width: -webkit-fill-available;
display: flex;
flex-direction: row;
flex-shrink: 0;
.module-avatar {
margin: auto;
}
}
h2 {
word-break: break-word;
}
.description {
margin: var(--margins-md) 0;
min-height: 4rem;
width: inherit;
color: var(--text-secondary-color);
text-align: center;
display: none;
}
// no double border (top and bottom) between two elements
&-item + &-item {
border-top: none;
}
.module-empty-state {
text-align: center;
}
.module-attachment-section__items {
&-media {
display: grid;
grid-template-columns: repeat(3, 1fr);
width: 100%;
}
&-documents {
width: 100%;
}
}
.module-media {
&-gallery {
&__tab-container {
padding-top: 1rem;
}
&__tab {
color: var(--text-primary-color);
font-weight: bold;
font-size: 0.9rem;
padding: 0.6rem;
opacity: 0.8;
&--active {
border-bottom: none;
opacity: 1;
&:after {
content: ''; /* This is necessary for the pseudo element to work. */
display: block;
margin: 0 auto;
width: 70%;
padding-top: 0.5rem;
border-bottom: 4px solid var(--primary-color);
}
}
}
&__content {
padding: var(--margins-xs);
margin-bottom: 1vh;
.module-media-grid-item__image,
.module-media-grid-item {
height: calc(
22vw / 4
); //.right-panel is 22vw and we want three rows with some space so divide it by 4
width: calc(
22vw / 4
); //.right-panel is 22vw and we want three rows with some space so divide it by 4
margin: auto;
}
}
}
}
}
// TODO is this being used
.conversation-content {
display: flex;
height: inherit;

@ -1,5 +1,6 @@
import React, { ReactNode } from 'react';
import styled, { CSSProperties } from 'styled-components';
import { Flex } from '../basic/Flex';
// NOTE Used for descendant components
export const StyledContent = styled.div<{ disabled: boolean }>`
@ -44,7 +45,9 @@ const StyledRoundedPanelButtonGroup = styled.div`
const PanelButtonContainer = styled.div`
overflow: auto;
min-height: 50px;
// TODO clear
/* min-height: 50px; */
min-height: 40px;
max-height: 100%;
`;
@ -108,3 +111,26 @@ export const PanelButton = (props: PanelButtonProps) => {
</StyledPanelButton>
);
};
const StyledSubtitle = styled.p<{ color?: string }>`
font-size: var(--font-size-xs);
margin: 0;
text-align: initial;
${props => props.color && `color: ${props.color};`}
`;
export const PanelButtonText = (props: { text: string; subtitle?: string; color?: string }) => {
return (
<Flex
container={true}
width={'100%'}
flexDirection={'column'}
alignItems={'flex-start'}
margin="0 var(--margins-lg) 0 var(--margins-lg)"
minWidth="0"
>
<StyledText color={props.color}>{props.text}</StyledText>
{!!props.subtitle && <StyledSubtitle color={props.color}>{props.subtitle}</StyledSubtitle>}
</Flex>
);
};

@ -1,20 +1,30 @@
import React from 'react';
import styled from 'styled-components';
import { SessionIcon, SessionIconType } from '../icon';
import { PanelButton, PanelButtonProps, StyledContent, StyledText } from './PanelButton';
import { PanelButton, PanelButtonProps, PanelButtonText, StyledContent } from './PanelButton';
interface PanelIconButton extends Omit<PanelButtonProps, 'children'> {
iconType: SessionIconType;
text: string;
subtitle?: string;
color?: string;
}
const IconContainer = styled.div`
flex-shrink: 0;
width: var(--toggle-width);
`;
export const PanelIconButton = (props: PanelIconButton) => {
const { iconType, text, disabled = false, onClick, dataTestId } = props;
const { iconType, text, subtitle, color, disabled = false, onClick, dataTestId } = props;
return (
<PanelButton disabled={disabled} onClick={onClick} dataTestId={dataTestId}>
<StyledContent disabled={disabled}>
<SessionIcon iconType={iconType} iconSize="medium" />
<StyledText>{text}</StyledText>
<IconContainer>
<SessionIcon iconType={iconType} iconColor={color} iconSize="medium" />
</IconContainer>
<PanelButtonText text={text} subtitle={subtitle} color={color} />
</StyledContent>
</PanelButton>
);

@ -1,8 +1,7 @@
import React from 'react';
import styled from 'styled-components';
import { Flex } from '../basic/Flex';
import { SessionRadio } from '../basic/SessionRadio';
import { PanelButton, PanelButtonProps, StyledContent, StyledText } from './PanelButton';
import { PanelButton, PanelButtonProps, PanelButtonText, StyledContent } from './PanelButton';
const StyledPanelButton = styled(PanelButton)`
padding-top: var(--margins-lg);
@ -15,19 +14,6 @@ const StyledPanelButton = styled(PanelButton)`
margin-inline-end: 0;
}
}
:first-child {
padding-top: 0;
}
:last-child {
padding-bottom: 0;
}
`;
const StyledSubtitle = styled.p`
font-size: var(--font-size-xs);
margin: 0;
`;
const StyledCheckContainer = styled.div`
@ -65,10 +51,7 @@ export const PanelRadioButton = (props: PanelRadioButtonProps) => {
dataTestId={dataTestId}
>
<StyledContent disabled={disabled}>
<Flex container={true} width={'100%'} flexDirection={'column'} alignItems={'flex-start'}>
<StyledText>{text}</StyledText>
{subtitle && <StyledSubtitle>{subtitle}</StyledSubtitle>}
</Flex>
<PanelButtonText text={text} subtitle={subtitle} />
<StyledCheckContainer>
<SessionRadio
active={isSelected}

@ -113,7 +113,7 @@ export const ConversationHeaderTitle = () => {
}
if (visibleSubtitle === 'disappearingMessages') {
dispatch(setRightOverlayMode('disappearing-messages'));
dispatch(setRightOverlayMode({ type: 'disappearing_messages', params: null }));
} else {
dispatch(resetRightOverlayMode());
}

@ -13,6 +13,7 @@ import {
getQuotedMessageToAnimate,
getShouldHighlightMessage,
} from '../../../../state/selectors/conversations';
import { canDisplayImage } from '../../../../types/Attachment';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
import { MessageAttachment } from './MessageAttachment';
import { MessageLinkPreview } from './MessageLinkPreview';
@ -156,12 +157,23 @@ export const MessageContent = (props: Props) => {
return null;
}
const { direction, text, timestamp, serverTimestamp, previews, quote } = contentProps;
const {
direction,
text,
timestamp,
serverTimestamp,
previews,
quote,
attachments,
} = contentProps;
const hasContentBeforeAttachment = !isEmpty(previews) || !isEmpty(quote) || !isEmpty(text);
const toolTipTitle = moment(serverTimestamp || timestamp).format('llll');
const isDetailViewAndSupportsAttachmentCarousel =
props.isDetailView && canDisplayImage(attachments);
return (
<StyledMessageContent
className={classNames('module-message__container', `module-message__container--${direction}`)}
@ -196,7 +208,7 @@ export const MessageContent = (props: Props) => {
<MessageText messageId={props.messageId} />
</StyledMessageOpaqueContent>
)}
{!isDeleted && (
{!isDeleted && isDetailViewAndSupportsAttachmentCarousel && !imageBroken ? null : (
<MessageAttachment
messageId={props.messageId}
imageBroken={imageBroken}

@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { Dispatch, useCallback, useEffect, useRef, useState } from 'react';
import { isNumber } from 'lodash';
import { Item, ItemParams, Menu, useContextMenu } from 'react-contexify';
import { useDispatch } from 'react-redux';
import { useClickAway, useMouse } from 'react-use';
import styled from 'styled-components';
import { isNumber } from 'lodash';
import { Data } from '../../../../data/data';
import { MessageInteraction } from '../../../../interactions';
@ -21,9 +21,11 @@ import {
import { MessageRenderingProps } from '../../../../models/messageType';
import { pushUnblockToSend } from '../../../../session/utils/Toast';
import {
openRightPanel,
showMessageDetailsView,
toggleSelectedMessageId,
} from '../../../../state/ducks/conversations';
import { setRightOverlayMode } from '../../../../state/ducks/section';
import {
useMessageAttachments,
useMessageBody,
@ -162,6 +164,29 @@ const RetryItem = ({ messageId }: MessageId) => {
return showRetry ? <Item onClick={onRetry}>{window.i18n('resend')}</Item> : null;
};
export const showMessageInfoOverlay = async ({
messageId,
dispatch,
}: {
messageId: string;
dispatch: Dispatch<any>;
}) => {
const found = await Data.getMessageById(messageId);
if (found) {
const messageDetailsProps = await found.getPropsForMessageDetail();
dispatch(showMessageDetailsView(messageDetailsProps));
dispatch(
setRightOverlayMode({
type: 'message_info',
params: { messageId, visibleAttachmentIndex: 0 },
})
);
dispatch(openRightPanel());
} else {
window.log.warn(`[showMessageInfoOverlay] Message ${messageId} not found in db`);
}
};
export const MessageContextMenu = (props: Props) => {
const { messageId, contextMenuId, enableReactions } = props;
const dispatch = useDispatch();
@ -214,16 +239,6 @@ export const MessageContextMenu = (props: Props) => {
[showEmojiPanel]
);
const onShowDetail = async () => {
const found = await Data.getMessageById(messageId);
if (found) {
const messageDetailsProps = await found.getPropsForMessageDetail();
dispatch(showMessageDetailsView(messageDetailsProps));
} else {
window.log.warn(`Message ${messageId} not found in db`);
}
};
const selectMessageText = window.i18n('selectMessage');
const deleteMessageJustForMeText = window.i18n('deleteJustForMe');
@ -361,9 +376,13 @@ export const MessageContextMenu = (props: Props) => {
{(isSent || !isOutgoing) && (
<Item onClick={onReply}>{window.i18n('replyToMessage')}</Item>
)}
{(!isPublic || isOutgoing) && (
<Item onClick={onShowDetail}>{window.i18n('moreInformation')}</Item>
)}
<Item
onClick={async () => {
await showMessageInfoOverlay({ messageId, dispatch });
}}
>
{window.i18n('moreInformation')}
</Item>
<RetryItem messageId={messageId} />
{isDeletable ? <Item onClick={onSelect}>{selectMessageText}</Item> : null}
{isDeletable && !isPublic ? (

@ -7,10 +7,7 @@ import { ToastUtils } from '../../../../session/utils';
import { openConversationToSpecificMessage } from '../../../../state/ducks/conversations';
import { StateType } from '../../../../state/reducer';
import { useMessageDirection } from '../../../../state/selectors';
import {
getMessageQuoteProps,
isMessageDetailView,
} from '../../../../state/selectors/conversations';
import { getMessageQuoteProps } from '../../../../state/selectors/conversations';
import { Quote } from './quote/Quote';
type Props = {
@ -22,7 +19,6 @@ export type MessageQuoteSelectorProps = Pick<MessageRenderingProps, 'quote' | 'd
export const MessageQuote = (props: Props) => {
const selected = useSelector((state: StateType) => getMessageQuoteProps(state, props.messageId));
const direction = useMessageDirection(props.messageId);
const isMessageDetailViewMode = useSelector(isMessageDetailView);
if (!selected || isEmpty(selected)) {
return null;
@ -48,11 +44,6 @@ export const MessageQuote = (props: Props) => {
return;
}
if (isMessageDetailViewMode) {
// trying to scroll while in the container while the message detail view is shown has unknown effects
return;
}
let conversationKey = String(quote.convoId);
let messageIdToNavigateTo = String(quote.id);
let quoteNotFoundInDB = false;

@ -1,15 +1,92 @@
import React from 'react';
import styled from 'styled-components';
import { useRightOverlayMode } from '../../../hooks/useUI';
import { Flex } from '../../basic/Flex';
import { OverlayRightPanelSettings } from './overlay/OverlayRightPanelSettings';
import { OverlayDisappearingMessages } from './overlay/disappearing-messages/OverlayDisappearingMessages';
const StyledRightPanel = styled(Flex)`
h2 {
word-break: break-word;
}
.description {
margin: var(--margins-md) 0;
min-height: 4rem;
width: inherit;
color: var(--text-secondary-color);
text-align: center;
display: none;
}
// no double border (top and bottom) between two elements
&-item + &-item {
border-top: none;
}
.module-empty-state {
text-align: center;
}
.module-attachment-section__items {
&-media {
display: grid;
grid-template-columns: repeat(3, 1fr);
width: 100%;
}
&-documents {
width: 100%;
}
}
.module-media {
&-gallery {
&__tab-container {
padding-top: 1rem;
}
&__tab {
color: var(--text-primary-color);
font-weight: bold;
font-size: 0.9rem;
padding: 0.6rem;
opacity: 0.8;
&--active {
border-bottom: none;
opacity: 1;
&:after {
content: ''; /* This is necessary for the pseudo element to work. */
display: block;
margin: 0 auto;
width: 70%;
padding-top: 0.5rem;
border-bottom: 4px solid var(--primary-color);
}
}
}
&__content {
padding: var(--margins-xs);
margin-bottom: 1vh;
.module-media-grid-item__image,
.module-media-grid-item {
height: calc(
var(--right-panel-width) / 4
); //.right-panel is var(--right-panel-width) and we want three rows with some space so divide it by 4
width: calc(
var(--right-panel-width) / 4
); //.right-panel is var(--right-panel-width) and we want three rows with some space so divide it by 4
margin: auto;
}
}
}
}
`;
const ClosableOverlay = () => {
const rightOverlayMode = useRightOverlayMode();
switch (rightOverlayMode) {
case 'disappearing-messages':
switch (rightOverlayMode?.type) {
case 'disappearing_messages':
return <OverlayDisappearingMessages />;
case 'message_info':
// TODO: copy this
// return <OverlayMessageInfo />;
return <></>;
default:
return <OverlayRightPanelSettings />;
}
@ -17,8 +94,15 @@ const ClosableOverlay = () => {
export const RightPanel = () => {
return (
<div className="right-panel">
<StyledRightPanel
container={true}
flexDirection={'column'}
alignItems={'center'}
width={'var(--right-panel-width)'}
height={'var(--right-panel-height)'}
className="right-panel"
>
<ClosableOverlay />
</div>
</StyledRightPanel>
);
};

@ -355,7 +355,7 @@ export const OverlayRightPanelSettings = () => {
iconType={'timer50'}
text={window.i18n('disappearingMessages')}
onClick={() => {
dispatch(setRightOverlayMode('disappearing-messages'));
dispatch(setRightOverlayMode({ type: 'disappearing_messages', params: null }));
}}
/>
</PanelButtonGroup>

@ -87,8 +87,17 @@ export function resetOverlayMode(): ResetOverlayModeActionType {
};
}
// TODO possibly more overlays here
export type RightOverlayMode = 'disappearing-messages';
type RightPanelDefaultState = { type: 'default'; params: null };
type RightPanelMessageInfoState = {
type: 'message_info';
params: { messageId: string; visibleAttachmentIndex: number | undefined };
};
type RightPanelDisappearingMessagesState = { type: 'disappearing_messages'; params: null };
export type RightOverlayMode =
| RightPanelDefaultState
| RightPanelMessageInfoState
| RightPanelDisappearingMessagesState;
export function setRightOverlayMode(overlayMode: RightOverlayMode): RightOverlayModeActionType {
return {
@ -126,7 +135,7 @@ export const initialSectionState: SectionStateType = {
focusedSettingsSection: undefined,
isAppFocused: false,
overlayMode: undefined,
rightOverlayMode: undefined,
rightOverlayMode: { type: 'default', params: null },
};
export type SectionStateType = {

Loading…
Cancel
Save