Emojify note and add non-nickname tooltip
This commit is contained in:
parent
4d794eaf14
commit
b6afa47126
9 changed files with 47 additions and 10 deletions
|
@ -1370,6 +1370,10 @@
|
||||||
"messageformat": "{nickname} <muted>({titleNoNickname})</muted>",
|
"messageformat": "{nickname} <muted>({titleNoNickname})</muted>",
|
||||||
"description": "Title of conversation when there is a nickname, example: 'Jim (James Smith)'"
|
"description": "Title of conversation when there is a nickname, example: 'Jim (James Smith)'"
|
||||||
},
|
},
|
||||||
|
"icu:AboutContactModal__TitleWithoutNickname__Tooltip": {
|
||||||
|
"messageformat": "“{title}” is the profile name this person set for themselves in Signal.",
|
||||||
|
"description": "Tooltip for the non-nickname title of a conversation."
|
||||||
|
},
|
||||||
"icu:AboutContactModal__verified": {
|
"icu:AboutContactModal__verified": {
|
||||||
"messageformat": "Verified",
|
"messageformat": "Verified",
|
||||||
"description": "Text of a button on About modal leading to a safety number modal"
|
"description": "Text of a button on About modal leading to a safety number modal"
|
||||||
|
|
|
@ -141,3 +141,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.AboutContactModal__TitleWithoutNickname__Tooltip {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { strictAssert } from '../util/assert';
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
nickname: z
|
nickname: z
|
||||||
.object({
|
.object({
|
||||||
givenName: z.string(),
|
givenName: z.string().nullable(),
|
||||||
familyName: z.string().nullable(),
|
familyName: z.string().nullable(),
|
||||||
})
|
})
|
||||||
.nullable(),
|
.nullable(),
|
||||||
|
|
|
@ -7,6 +7,8 @@ import type { LocalizerType } from '../types/I18N';
|
||||||
import { Button, ButtonVariant } from './Button';
|
import { Button, ButtonVariant } from './Button';
|
||||||
import { Modal } from './Modal';
|
import { Modal } from './Modal';
|
||||||
import { Linkify } from './conversation/Linkify';
|
import { Linkify } from './conversation/Linkify';
|
||||||
|
import type { RenderTextCallbackType } from '../types/Util';
|
||||||
|
import { Emojify } from './conversation/Emojify';
|
||||||
|
|
||||||
export type NotePreviewModalProps = Readonly<{
|
export type NotePreviewModalProps = Readonly<{
|
||||||
conversation: ConversationType;
|
conversation: ConversationType;
|
||||||
|
@ -15,6 +17,10 @@ export type NotePreviewModalProps = Readonly<{
|
||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
const renderNonLink: RenderTextCallbackType = ({ key, text }) => {
|
||||||
|
return <Emojify key={key} text={text} />;
|
||||||
|
};
|
||||||
|
|
||||||
export function NotePreviewModal({
|
export function NotePreviewModal({
|
||||||
conversation,
|
conversation,
|
||||||
i18n,
|
i18n,
|
||||||
|
@ -40,7 +46,7 @@ export function NotePreviewModal({
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div dir="auto">
|
<div dir="auto">
|
||||||
<Linkify text={conversation.note ?? ''} />
|
<Linkify text={conversation.note ?? ''} renderNonLink={renderNonLink} />
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
// Copyright 2023 Signal Messenger, LLC
|
// Copyright 2023 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Emojify } from './conversation/Emojify';
|
import { Emojify } from './conversation/Emojify';
|
||||||
|
import { bidiIsolate } from '../util/unicodeBidi';
|
||||||
|
|
||||||
export function UserText({ text }: { text: string }): JSX.Element {
|
export function UserText({ text }: { text: string }): JSX.Element {
|
||||||
|
const normalizedText = useMemo(() => {
|
||||||
|
return bidiIsolate(text);
|
||||||
|
}, [text]);
|
||||||
return (
|
return (
|
||||||
<span dir="auto">
|
<span dir="auto">
|
||||||
<Emojify text={text} />
|
<Emojify text={normalizedText} />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
areNicknamesEnabled,
|
areNicknamesEnabled,
|
||||||
canHaveNicknameAndNote,
|
canHaveNicknameAndNote,
|
||||||
} from '../../util/nicknames';
|
} from '../../util/nicknames';
|
||||||
|
import { Tooltip, TooltipPlacement } from '../Tooltip';
|
||||||
|
|
||||||
function muted(parts: Array<string | JSX.Element>) {
|
function muted(parts: Array<string | JSX.Element>) {
|
||||||
return (
|
return (
|
||||||
|
@ -150,7 +151,7 @@ export function AboutContactModal({
|
||||||
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--profile" />
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--profile" />
|
||||||
|
|
||||||
{canHaveNicknameAndNote(conversation) &&
|
{canHaveNicknameAndNote(conversation) &&
|
||||||
conversation.nicknameGivenName &&
|
(conversation.nicknameGivenName || conversation.nicknameFamilyName) &&
|
||||||
conversation.titleNoNickname ? (
|
conversation.titleNoNickname ? (
|
||||||
<span>
|
<span>
|
||||||
<Intl
|
<Intl
|
||||||
|
@ -159,7 +160,24 @@ export function AboutContactModal({
|
||||||
components={{
|
components={{
|
||||||
nickname: <UserText text={conversation.title} />,
|
nickname: <UserText text={conversation.title} />,
|
||||||
titleNoNickname: (
|
titleNoNickname: (
|
||||||
<UserText text={conversation.titleNoNickname} />
|
<Tooltip
|
||||||
|
className="AboutContactModal__TitleWithoutNickname__Tooltip"
|
||||||
|
direction={TooltipPlacement.Top}
|
||||||
|
content={
|
||||||
|
<Intl
|
||||||
|
i18n={i18n}
|
||||||
|
id="icu:AboutContactModal__TitleWithoutNickname__Tooltip"
|
||||||
|
components={{
|
||||||
|
title: (
|
||||||
|
<UserText text={conversation.titleNoNickname} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
delay={0}
|
||||||
|
>
|
||||||
|
<UserText text={conversation.titleNoNickname} />
|
||||||
|
</Tooltip>
|
||||||
),
|
),
|
||||||
muted,
|
muted,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -38,7 +38,8 @@ export function ProfileChangeNotification({
|
||||||
contents={<Emojify text={message} />}
|
contents={<Emojify text={message} />}
|
||||||
button={
|
button={
|
||||||
areNicknamesEnabled() &&
|
areNicknamesEnabled() &&
|
||||||
changedContact.nicknameGivenName != null && (
|
(changedContact.nicknameGivenName != null ||
|
||||||
|
changedContact.nicknameFamilyName != null) && (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleOpenEditNicknameAndNoteModal}
|
onClick={handleOpenEditNicknameAndNoteModal}
|
||||||
size={ButtonSize.Small}
|
size={ButtonSize.Small}
|
||||||
|
|
|
@ -203,8 +203,8 @@ export async function toContactRecord(
|
||||||
contactRecord.familyName = profileFamilyName;
|
contactRecord.familyName = profileFamilyName;
|
||||||
}
|
}
|
||||||
const nicknameGivenName = conversation.get('nicknameGivenName');
|
const nicknameGivenName = conversation.get('nicknameGivenName');
|
||||||
if (nicknameGivenName) {
|
const nicknameFamilyName = conversation.get('nicknameFamilyName');
|
||||||
const nicknameFamilyName = conversation.get('nicknameFamilyName');
|
if (nicknameGivenName || nicknameFamilyName) {
|
||||||
contactRecord.nickname = {
|
contactRecord.nickname = {
|
||||||
given: nicknameGivenName,
|
given: nicknameGivenName,
|
||||||
family: nicknameFamilyName,
|
family: nicknameFamilyName,
|
||||||
|
|
|
@ -4680,7 +4680,7 @@ export function updateLastMessage(
|
||||||
|
|
||||||
export type NicknameAndNote = ReadonlyDeep<{
|
export type NicknameAndNote = ReadonlyDeep<{
|
||||||
nickname: {
|
nickname: {
|
||||||
givenName: string;
|
givenName: string | null;
|
||||||
familyName: string | null;
|
familyName: string | null;
|
||||||
} | null;
|
} | null;
|
||||||
note: string | null;
|
note: string | null;
|
||||||
|
|
Loading…
Reference in a new issue