UI fixes for conversation details screen

This commit is contained in:
Josh Perez 2021-02-01 17:57:42 -05:00 committed by GitHub
parent ddebbf8121
commit 267ae80442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 134 additions and 51 deletions

View File

@ -0,0 +1,4 @@
<svg id="Export" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<rect x="12.12" y="20" width="0.58" height="1.5"/>
<path d="M21.38,12A9.45,9.45,0,0,1,12,21.5,9.5,9.5,0,1,1,18.84,5.28l1,1-.35-1.3V2.56H21V8.5H15V7h2.39l1.42.38-1-1A8,8,0,0,0,4.12,12a7.88,7.88,0,1,0,15.76,0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 318 B

View File

@ -2924,6 +2924,12 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
.module-conversation-header__title-clickable {
cursor: pointer;
&:focus {
@include mouse-mode {
outline: none;
}
}
}
.module-conversation-header__note-to-self {
@ -3189,7 +3195,7 @@ button.module-conversation-details__action-button {
}
&__title {
@include font-body-1-bold;
@include font-title-1;
padding-top: 12px;
padding-bottom: 8px;
}
@ -3205,6 +3211,14 @@ button.module-conversation-details__action-button {
}
}
&__leave-group {
color: $color-accent-red;
}
&__block-group {
color: $color-accent-red;
}
&__tabs {
display: flex;
justify-content: space-around;
@ -3342,8 +3356,7 @@ button.module-conversation-details__action-button {
&--reset {
&::after {
transform: scaleX(-1);
-webkit-mask: url(../images/icons/v2/undo-24.svg) no-repeat center;
-webkit-mask: url(../images/icons/v2/refresh-24.svg) no-repeat center;
@include light-theme {
background-color: $color-gray-75;
@ -3430,6 +3443,7 @@ button.module-conversation-details__action-button {
display: flex;
justify-content: center;
padding: 0 20px;
padding-bottom: 24px;
.module-media-grid-item {
border-radius: 4px;
@ -3458,6 +3472,13 @@ button.module-conversation-details__action-button {
background: none;
border: none;
padding: 0;
@include light-theme {
color: $color-gray-95;
}
@include dark-theme {
color: $color-gray-05;
}
}
}

View File

@ -487,13 +487,15 @@ export class ConversationHeader extends React.Component<PropsType> {
private renderHeader(): JSX.Element {
const {
conversationTitle,
groupVersion,
id,
isMe,
onShowContactModal,
onShowConversationDetails,
type,
} = this.props;
if (conversationTitle) {
if (conversationTitle !== undefined) {
return (
<div className="module-conversation-header__title-flex">
<div className="module-conversation-header__title">
@ -503,6 +505,35 @@ export class ConversationHeader extends React.Component<PropsType> {
);
}
const hasGV2AdminEnabled =
groupVersion === 2 &&
window.Signal.RemoteConfig.isEnabled('desktop.gv2Admin');
if (type === 'group' && hasGV2AdminEnabled) {
const onHeaderClick = () => onShowConversationDetails();
const onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === 'Enter' || e.key === ' ') {
e.stopPropagation();
e.preventDefault();
onShowConversationDetails();
}
};
return (
<div
className="module-conversation-header__title-flex module-conversation-header__title-clickable"
onClick={onHeaderClick}
onKeyDown={onKeyDown}
role="button"
tabIndex={0}
>
{this.renderAvatar()}
{this.renderTitle()}
</div>
);
}
if (type === 'group' || isMe) {
return (
<div className="module-conversation-header__title-flex">

View File

@ -37,7 +37,11 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
icon="leave"
/>
}
label={i18n('ConversationDetailsActions--leave-group')}
label={
<div className="module-conversation-details__leave-group">
{i18n('ConversationDetailsActions--leave-group')}
</div>
}
/>
<PanelRow
onClick={() => setConfirmingBlock(true)}
@ -47,7 +51,11 @@ export const ConversationDetailsActions: React.ComponentType<Props> = ({
icon="block"
/>
}
label={i18n('ConversationDetailsActions--block-group')}
label={
<div className="module-conversation-details__block-group">
{i18n('ConversationDetailsActions--block-group')}
</div>
}
/>
</PanelSection>

View File

@ -45,16 +45,32 @@ const createProps = (overrideProps: Partial<Props>): Props => ({
memberships: overrideProps.memberships || [],
});
story.add('Basic', () => {
const memberships = createMemberships(10);
story.add('Few', () => {
const memberships = createMemberships(3);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Few', () => {
const memberships = createMemberships(3);
story.add('Limit', () => {
const memberships = createMemberships(5);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Limit +1', () => {
const memberships = createMemberships(6);
const props = createProps({ memberships });
return <ConversationDetailsMembershipList {...props} />;
});
story.add('Limit +2', () => {
const memberships = createMemberships(7);
const props = createProps({ memberships });

View File

@ -24,7 +24,7 @@ export type Props = {
i18n: LocalizerType;
};
const INITIAL_MEMBER_COUNT = 5;
const MAX_MEMBER_COUNT = 5;
export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
memberships,
@ -33,44 +33,47 @@ export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
}) => {
const [showAllMembers, setShowAllMembers] = React.useState<boolean>(false);
const shouldHideRestMembers = memberships.length - MAX_MEMBER_COUNT > 1;
const membersToShow =
shouldHideRestMembers && !showAllMembers
? MAX_MEMBER_COUNT
: memberships.length;
return (
<PanelSection
title={i18n('ConversationDetailsMembershipList--title', [
memberships.length.toString(),
])}
>
{memberships
.slice(0, showAllMembers ? undefined : INITIAL_MEMBER_COUNT)
.map(({ isAdmin, member }) => (
<PanelRow
key={member.id}
onClick={() => showContactModal(member.id)}
icon={
<Avatar
conversationType="direct"
i18n={i18n}
size={32}
{...member}
/>
}
label={member.title}
right={isAdmin ? i18n('GroupV2--admin') : ''}
/>
))}
{showAllMembers === false &&
memberships.length > INITIAL_MEMBER_COUNT && (
<PanelRow
className="module-conversation-details-membership-list--show-all"
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsMembershipList--show-all')}
icon="down"
/>
}
onClick={() => setShowAllMembers(true)}
label={i18n('ConversationDetailsMembershipList--show-all')}
/>
)}
{memberships.slice(0, membersToShow).map(({ isAdmin, member }) => (
<PanelRow
key={member.id}
onClick={() => showContactModal(member.id)}
icon={
<Avatar
conversationType="direct"
i18n={i18n}
size={32}
{...member}
/>
}
label={member.title}
right={isAdmin ? i18n('GroupV2--admin') : ''}
/>
))}
{showAllMembers === false && shouldHideRestMembers && (
<PanelRow
className="module-conversation-details-membership-list--show-all"
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsMembershipList--show-all')}
icon="down"
/>
}
onClick={() => setShowAllMembers(true)}
label={i18n('ConversationDetailsMembershipList--show-all')}
/>
)}
</PanelSection>
);
};

View File

@ -19,7 +19,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
icon: boolean('with icon', overrideProps.icon !== undefined) ? (
<ConversationDetailsIcon ariaLabel="timer" icon="timer" />
) : null,
label: text('label', overrideProps.label || ''),
label: text('label', (overrideProps.label as string) || ''),
info: text('info', overrideProps.info || ''),
right: text('right', (overrideProps.right as string) || ''),
actions: boolean('with action', overrideProps.actions !== undefined) ? (

View File

@ -9,7 +9,7 @@ export type Props = {
alwaysShowActions?: boolean;
className?: string;
icon?: React.ReactNode;
label: string;
label: string | React.ReactNode;
info?: string;
right?: string | React.ReactNode;
actions?: React.ReactNode;
@ -30,15 +30,15 @@ export const PanelRow: React.ComponentType<Props> = ({
}) => {
const content = (
<>
{icon && <div className={bem('icon')}>{icon}</div>}
{icon !== undefined ? <div className={bem('icon')}>{icon}</div> : null}
<div className={bem('label')}>
<div>{label}</div>
{info && <div className={bem('info')}>{info}</div>}
{info !== undefined ? <div className={bem('info')}>{info}</div> : null}
</div>
{right && <div className={bem('right')}>{right}</div>}
{actions && (
{right !== undefined ? <div className={bem('right')}>{right}</div> : null}
{actions !== undefined ? (
<div className={alwaysShowActions ? '' : bem('actions')}>{actions}</div>
)}
) : null}
</>
);

View File

@ -274,7 +274,7 @@ export function buildGroupLink(conversation: ConversationModel): string {
const bytes = proto.toArrayBuffer();
const hash = toWebSafeBase64(window.Signal.Crypto.arrayBufferToBase64(bytes));
return `sgnl://signal.group/#${hash}`;
return `https://signal.group/#${hash}`;
}
export function parseGroupLink(