UI fixes for conversation details screen
This commit is contained in:
parent
ddebbf8121
commit
267ae80442
9 changed files with 134 additions and 51 deletions
4
images/icons/v2/refresh-24.svg
Normal file
4
images/icons/v2/refresh-24.svg
Normal 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 |
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 });
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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) ? (
|
||||
|
|
|
@ -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}
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue