mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-02 07:06:41 +03:00
Merge branch 'release/next-js' of https://github.com/urbit/urbit into npm-packages
This commit is contained in:
commit
2b30227f0f
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f4b93e4d91e42c8444bb22447a0ae7d969ec552ba2d0f4b87a8dd20a41709d4e
|
oid sha256:ec58605002fafbe6f3a5988fe1db4bd31e2fd40370b30e96db64a98c8f7da0ea
|
||||||
size 9345380
|
size 9474412
|
||||||
|
@ -94,16 +94,18 @@
|
|||||||
++ rolo
|
++ rolo
|
||||||
^- rolodex:store
|
^- rolodex:store
|
||||||
=/ ugroup (scry-group:grp resource)
|
=/ ugroup (scry-group:grp resource)
|
||||||
|
=/ =rolodex:store
|
||||||
|
(scry-for:con rolodex:store /all)
|
||||||
%- ~(gas by *rolodex:store)
|
%- ~(gas by *rolodex:store)
|
||||||
?~ ugroup
|
?~ ugroup
|
||||||
=/ c=(unit contact:store) (get-contact:con our.bowl)
|
=/ c=(unit contact:store) (~(get by rolodex) our.bowl)
|
||||||
?~ c
|
?~ c
|
||||||
[our.bowl *contact:store]~
|
[our.bowl *contact:store]~
|
||||||
[our.bowl u.c]~
|
[our.bowl u.c]~
|
||||||
%+ murn ~(tap in (members:grp resource))
|
%+ murn ~(tap in (members:grp resource))
|
||||||
|= s=ship
|
|= s=ship
|
||||||
^- (unit [ship contact:store])
|
^- (unit [ship contact:store])
|
||||||
=/ c=(unit contact:store) (get-contact:con s)
|
=/ c=(unit contact:store) (~(get by rolodex) s)
|
||||||
?~(c ~ `[s u.c])
|
?~(c ~ `[s u.c])
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
|
@ -104,10 +104,18 @@
|
|||||||
|= [rolo=rolodex:store is-public=?]
|
|= [rolo=rolodex:store is-public=?]
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
=/ our-contact (~(got by rolodex) our.bowl)
|
=/ our-contact (~(got by rolodex) our.bowl)
|
||||||
=. rolodex (~(uni by rolodex) rolo)
|
=/ diff-rolo=rolodex:store
|
||||||
=. rolodex (~(put by rolodex) our.bowl our-contact)
|
%- ~(gas by *rolodex:store)
|
||||||
:_ state(rolodex rolodex)
|
%+ skim ~(tap in rolo)
|
||||||
(send-diff [%initial rolodex is-public] %.n)
|
|= [=ship =contact:store]
|
||||||
|
?~ local-con=(~(get by rolodex) ship) %.y
|
||||||
|
(gth last-updated.contact last-updated.u.local-con)
|
||||||
|
=/ new-rolo=rolodex:store
|
||||||
|
(~(uni by rolodex) diff-rolo)
|
||||||
|
=. new-rolo (~(put by new-rolo) our.bowl our-contact)
|
||||||
|
?: =(new-rolo rolodex) `state
|
||||||
|
:_ state(rolodex new-rolo)
|
||||||
|
(send-diff [%initial new-rolo is-public] %.n)
|
||||||
::
|
::
|
||||||
++ handle-add
|
++ handle-add
|
||||||
|= [=ship =contact:store]
|
|= [=ship =contact:store]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/- glob
|
/- glob
|
||||||
/+ default-agent, verb, dbug
|
/+ default-agent, verb, dbug
|
||||||
|%
|
|%
|
||||||
++ hash 0v3.t4lg5.84a6h.2bi2s.ni2p9.32uor
|
++ hash 0v7.iotki.j1ptb.mk9vm.borai.jfcr1
|
||||||
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
||||||
+$ all-states
|
+$ all-states
|
||||||
$% state-0
|
$% state-0
|
||||||
|
@ -24,6 +24,6 @@
|
|||||||
<div id="portal-root"></div>
|
<div id="portal-root"></div>
|
||||||
<script src="/~landscape/js/channel.js"></script>
|
<script src="/~landscape/js/channel.js"></script>
|
||||||
<script src="/~landscape/js/session.js"></script>
|
<script src="/~landscape/js/session.js"></script>
|
||||||
<script src="/~landscape/js/bundle/index.dcdc4301b299cb03bad0.js"></script>
|
<script src="/~landscape/js/bundle/index.096bb7cb32b754071b13.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -59,18 +59,16 @@ const edit = (json: ContactUpdate, state: S) => {
|
|||||||
if (!field) {
|
if (!field) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const contact = state.contacts?.[ship];
|
|
||||||
const value = data['edit-field'][field];
|
|
||||||
if(!contact) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const value = data['edit-field'][field];
|
||||||
|
|
||||||
if(field === 'add-group') {
|
if(field === 'add-group') {
|
||||||
contact.groups.push(value);
|
state.contacts[ship].groups.push(value);
|
||||||
} else if (field === 'remove-group') {
|
} else if (field === 'remove-group') {
|
||||||
contact.groups = contact.groups.filter(g => g !== value);
|
state.contacts[ship].groups =
|
||||||
|
state.contacts[ship].groups.filter(g => g !== value);
|
||||||
} else {
|
} else {
|
||||||
contact[field] = value;
|
state.contacts[ship][field] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -80,52 +80,52 @@ export function ChatResource(props: ChatResourceProps) {
|
|||||||
}, [station]);
|
}, [station]);
|
||||||
|
|
||||||
const [showBanner, setShowBanner] = useState(false);
|
const [showBanner, setShowBanner] = useState(false);
|
||||||
|
const [hasLoadedAllowed, setHasLoadedAllowed] = useState(false);
|
||||||
const [recipients, setRecipients] = useState([]);
|
const [recipients, setRecipients] = useState([]);
|
||||||
|
|
||||||
const res = resourceFromPath(groupPath);
|
const res = resourceFromPath(groupPath);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!res) {
|
if (!res) { return; }
|
||||||
return;
|
if (!group) { return; }
|
||||||
}
|
if (group.hidden) {
|
||||||
if (!group) {
|
const members = _.compact(await Promise.all(
|
||||||
return;
|
Array.from(group.members)
|
||||||
}
|
.map(s => {
|
||||||
if (group.hidden) {
|
const ship = `~${s}`;
|
||||||
const members = _.compact(await Promise.all(
|
if(s === window.ship) {
|
||||||
Array.from(group.members)
|
return Promise.resolve(null);
|
||||||
.map((s) => {
|
}
|
||||||
const ship = `~${s}`;
|
return props.api.contacts.fetchIsAllowed(
|
||||||
if(s === window.ship) {
|
`~${window.ship}`,
|
||||||
return Promise.resolve(null);
|
'personal',
|
||||||
}
|
ship,
|
||||||
return props.api.contacts.fetchIsAllowed(
|
true
|
||||||
`~${window.ship}`,
|
).then(isAllowed => {
|
||||||
'personal',
|
return isAllowed ? null : ship;
|
||||||
ship,
|
});
|
||||||
true
|
})
|
||||||
).then((isAllowed) => {
|
));
|
||||||
return isAllowed ? null : ship;
|
|
||||||
});
|
if(members.length > 0) {
|
||||||
})
|
setShowBanner(true);
|
||||||
));
|
setRecipients(members);
|
||||||
|
} else {
|
||||||
|
setShowBanner(false);
|
||||||
|
}
|
||||||
|
|
||||||
if(members.length > 0) {
|
|
||||||
setShowBanner(true);
|
|
||||||
setRecipients(members);
|
|
||||||
} else {
|
} else {
|
||||||
setShowBanner(false);
|
const groupShared = await props.api.contacts.fetchIsAllowed(
|
||||||
|
`~${window.ship}`,
|
||||||
|
'personal',
|
||||||
|
res.ship,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
setShowBanner(!groupShared);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const groupShared = await props.api.contacts.fetchIsAllowed(
|
setHasLoadedAllowed(true);
|
||||||
`~${window.ship}`,
|
|
||||||
'personal',
|
|
||||||
res.ship,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
setShowBanner(!groupShared);
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
}, [groupPath]);
|
}, [groupPath]);
|
||||||
|
|
||||||
@ -153,7 +153,10 @@ export function ChatResource(props: ChatResourceProps) {
|
|||||||
history={props.history}
|
history={props.history}
|
||||||
graph={graph}
|
graph={graph}
|
||||||
unreadCount={unreadCount}
|
unreadCount={unreadCount}
|
||||||
contacts={!showBanner ? contacts : modifiedContacts}
|
contacts={
|
||||||
|
(!showBanner && hasLoadedAllowed) ?
|
||||||
|
contacts : modifiedContacts
|
||||||
|
}
|
||||||
association={props.association}
|
association={props.association}
|
||||||
associations={props.associations}
|
associations={props.associations}
|
||||||
groups={props.groups}
|
groups={props.groups}
|
||||||
@ -168,9 +171,13 @@ export function ChatResource(props: ChatResourceProps) {
|
|||||||
ref={chatInput}
|
ref={chatInput}
|
||||||
api={props.api}
|
api={props.api}
|
||||||
station={station}
|
station={station}
|
||||||
ourContact={!showBanner ? ourContact : null}
|
ourContact={
|
||||||
|
(!showBanner && hasLoadedAllowed) ? ourContact : null
|
||||||
|
}
|
||||||
envelopes={[]}
|
envelopes={[]}
|
||||||
contacts={contacts}
|
contacts={
|
||||||
|
(!showBanner && hasLoadedAllowed) ? contacts : modifiedContacts
|
||||||
|
}
|
||||||
onUnmount={appendUnsent}
|
onUnmount={appendUnsent}
|
||||||
s3={props.s3}
|
s3={props.s3}
|
||||||
placeholder="Message..."
|
placeholder="Message..."
|
||||||
|
@ -95,16 +95,8 @@ h2 {
|
|||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.embed-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 14rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-container iframe {
|
.embed-container iframe {
|
||||||
max-width: 24rem;
|
max-width: 100%;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 26rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mh-16 {
|
.mh-16 {
|
||||||
|
@ -7,14 +7,15 @@ import {
|
|||||||
Row,
|
Row,
|
||||||
BaseImage,
|
BaseImage,
|
||||||
Text
|
Text
|
||||||
} from '@tlon/indigo-react';
|
} from "@tlon/indigo-react";
|
||||||
|
|
||||||
|
import RichText from '~/views/components/RichText'
|
||||||
|
import useLocalState from "~/logic/state/local";
|
||||||
import { Sigil } from '~/logic/lib/sigil';
|
import { Sigil } from '~/logic/lib/sigil';
|
||||||
import { ViewProfile } from './ViewProfile';
|
import { ViewProfile } from './ViewProfile';
|
||||||
import { EditProfile } from './EditProfile';
|
import { EditProfile } from './EditProfile';
|
||||||
import { SetStatusBarModal } from '~/views/components/SetStatusBarModal';
|
import { SetStatusBarModal } from '~/views/components/SetStatusBarModal';
|
||||||
import { uxToHex } from '~/logic/lib/util';
|
import { uxToHex } from '~/logic/lib/util';
|
||||||
import useLocalState from '~/logic/state/local';
|
|
||||||
import { useTutorialModal } from '~/views/components/useTutorialModal';
|
import { useTutorialModal } from '~/views/components/useTutorialModal';
|
||||||
|
|
||||||
export function Profile(props: any): ReactElement {
|
export function Profile(props: any): ReactElement {
|
||||||
@ -61,8 +62,9 @@ export function Profile(props: any): ReactElement {
|
|||||||
width="100%"
|
width="100%"
|
||||||
>
|
>
|
||||||
<Row alignItems="center" justifyContent="space-between">
|
<Row alignItems="center" justifyContent="space-between">
|
||||||
|
<Row>
|
||||||
{ship === `~${window.ship}` ? (
|
{ship === `~${window.ship}` ? (
|
||||||
<Row>
|
<>
|
||||||
<Text
|
<Text
|
||||||
py='2'
|
py='2'
|
||||||
cursor='pointer'
|
cursor='pointer'
|
||||||
@ -79,14 +81,12 @@ export function Profile(props: any): ReactElement {
|
|||||||
ship={`~${window.ship}`}
|
ship={`~${window.ship}`}
|
||||||
contact={contact}
|
contact={contact}
|
||||||
/>
|
/>
|
||||||
</Row>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<Text maxWidth='18rem' overflowX='hidden'
|
</Row>
|
||||||
textOverflow="ellipsis"
|
<RichText mb='0' py='2' disableRemoteContent maxWidth='18rem' overflowX='hidden' textOverflow="ellipsis"
|
||||||
whiteSpace="nowrap"
|
whiteSpace="nowrap"
|
||||||
overflow="hidden" display="inline-block"
|
overflow="hidden" display="inline-block" verticalAlign="middle">{contact?.status ?? ""}</RichText>
|
||||||
verticalAlign="middle"
|
|
||||||
>{contact?.status ?? ''}</Text>
|
|
||||||
</Row>
|
</Row>
|
||||||
<Row width="100%" height="300px">
|
<Row width="100%" height="300px">
|
||||||
{cover}
|
{cover}
|
||||||
|
@ -59,7 +59,7 @@ export function InviteItem(props: InviteItemProps) {
|
|||||||
|
|
||||||
if (props.groups?.[resource]?.hidden) {
|
if (props.groups?.[resource]?.hidden) {
|
||||||
const { metadata } = associations.graph[resource];
|
const { metadata } = associations.graph[resource];
|
||||||
if (name.startsWith('dm--')) {
|
if (metadata?.module === 'chat') {
|
||||||
history.push(`/~landscape/messages/resource/${metadata.module}${resource}`);
|
history.push(`/~landscape/messages/resource/${metadata.module}${resource}`);
|
||||||
} else {
|
} else {
|
||||||
history.push(`/~landscape/home/resource/${metadata.module}${resource}`);
|
history.push(`/~landscape/home/resource/${metadata.module}${resource}`);
|
||||||
@ -122,10 +122,7 @@ export function InviteItem(props: InviteItemProps) {
|
|||||||
<JoinSkeleton status={status} gapY="3">
|
<JoinSkeleton status={status} gapY="3">
|
||||||
<Row py="1" alignItems="center">
|
<Row py="1" alignItems="center">
|
||||||
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
<Icon display="block" color="blue" icon="Bullet" mr="2" />
|
||||||
<Text mr="1">You are joining a DM with</Text>
|
<Text mr="1">Joining direct message...</Text>
|
||||||
<Text mr="1" mono>
|
|
||||||
{cite('~hastuc-dibtux')}
|
|
||||||
</Text>
|
|
||||||
</Row>
|
</Row>
|
||||||
</JoinSkeleton>
|
</JoinSkeleton>
|
||||||
);
|
);
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
ColProps,
|
ColProps,
|
||||||
Icon
|
Icon
|
||||||
} from '@tlon/indigo-react';
|
} from '@tlon/indigo-react';
|
||||||
|
import RichText from './RichText';
|
||||||
import { withLocalState } from '~/logic/state/local';
|
import { withLocalState } from '~/logic/state/local';
|
||||||
import { ProfileStatus } from './ProfileStatus';
|
import { ProfileStatus } from './ProfileStatus';
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ class ProfileOverlay extends PureComponent<ProfileOverlayProps, Record<string, n
|
|||||||
>
|
>
|
||||||
{img}
|
{img}
|
||||||
</Box>
|
</Box>
|
||||||
<Col alignItems="end" justifyContent="flex-end" overflow="hidden">
|
<Col alignItems="end" justifyContent="flex-end" overflow="hidden" minWidth='0'>
|
||||||
<Row width="100%" >
|
<Row width="100%" >
|
||||||
<Text
|
<Text
|
||||||
fontWeight='600'
|
fontWeight='600'
|
||||||
@ -153,9 +154,12 @@ class ProfileOverlay extends PureComponent<ProfileOverlayProps, Record<string, n
|
|||||||
contact={contact}
|
contact={contact}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text gray>
|
<RichText display='inline-block' width='100%' minWidth='0' textOverflow='ellipsis'
|
||||||
|
overflow='hidden'
|
||||||
|
whiteSpace='pre'
|
||||||
|
lineHeight="tall" disableRemoteContent gray>
|
||||||
{contact?.status ? contact.status : ''}
|
{contact?.status ? contact.status : ''}
|
||||||
</Text>
|
</RichText>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -33,10 +33,10 @@ const RichText = React.memo(({ disableRemoteContent, ...props }) => (
|
|||||||
videoShown: false,
|
videoShown: false,
|
||||||
oembedShown: false
|
oembedShown: false
|
||||||
} : null;
|
} : null;
|
||||||
if (hasProvider(linkProps.href)) {
|
if (!disableRemoteContent && hasProvider(linkProps.href)) {
|
||||||
return <RemoteContent className="mw-100" url={linkProps.href} />;
|
return <RemoteContent className="mw-100" url={linkProps.href} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <BaseAnchor target='_blank' rel='noreferrer noopener' borderBottom='1px solid' remoteContentPolicy={remoteContentPolicy} {...linkProps}>{linkProps.children}</BaseAnchor>;
|
return <BaseAnchor target='_blank' rel='noreferrer noopener' borderBottom='1px solid' remoteContentPolicy={remoteContentPolicy} {...linkProps}>{linkProps.children}</BaseAnchor>;
|
||||||
},
|
},
|
||||||
linkReference: (linkProps) => {
|
linkReference: (linkProps) => {
|
||||||
|
@ -107,7 +107,7 @@ const StatusBar = (props) => {
|
|||||||
width="auto"
|
width="auto"
|
||||||
alignY="top"
|
alignY="top"
|
||||||
alignX="right"
|
alignX="right"
|
||||||
flexShrink={0}
|
flexShrink={'0'}
|
||||||
options={
|
options={
|
||||||
<Col
|
<Col
|
||||||
mt='6'
|
mt='6'
|
||||||
|
@ -39,8 +39,10 @@ export function GroupsPane(props: GroupsPaneProps) {
|
|||||||
const relativePath = (path: string) => baseUrl + path;
|
const relativePath = (path: string) => baseUrl + path;
|
||||||
const groupPath = getGroupFromWorkspace(workspace);
|
const groupPath = getGroupFromWorkspace(workspace);
|
||||||
|
|
||||||
const groupContacts = (groupPath && contacts[groupPath]) || undefined;
|
const groupContacts = Object.assign({}, ...Array.from(groups?.[groupPath]?.members ?? []).filter(e => contacts[`~${e}`]).map(e => {
|
||||||
const rootIdentity = contacts?.['/~/default']?.[window.ship];
|
return {[e]: contacts[`~${e}`]};
|
||||||
|
})) || {};
|
||||||
|
const rootIdentity = contacts?.["/~/default"]?.[window.ship];
|
||||||
const groupAssociation =
|
const groupAssociation =
|
||||||
(groupPath && associations.groups[groupPath]) || undefined;
|
(groupPath && associations.groups[groupPath]) || undefined;
|
||||||
const group = (groupPath && groups[groupPath]) || undefined;
|
const group = (groupPath && groups[groupPath]) || undefined;
|
||||||
|
@ -101,7 +101,7 @@ export function NewChannel(props: NewChannelProps & RouteComponentProps): ReactE
|
|||||||
await waiter(p => Boolean(p?.groups?.[`/ship/~${window.ship}/${resId}`]));
|
await waiter(p => Boolean(p?.groups?.[`/ship/~${window.ship}/${resId}`]));
|
||||||
}
|
}
|
||||||
actions.setStatus({ success: null });
|
actions.setStatus({ success: null });
|
||||||
const resourceUrl = parentPath(location.pathname);
|
const resourceUrl = (location.pathname.includes("/messages")) ? "/~landscape/messages" : parentPath(location.pathname);
|
||||||
history.push(
|
history.push(
|
||||||
`${resourceUrl}/resource/${moduleType}/ship/~${window.ship}/${resId}`
|
`${resourceUrl}/resource/${moduleType}/ship/~${window.ship}/${resId}`
|
||||||
);
|
);
|
||||||
|
@ -31,10 +31,12 @@ import GlobalApi from '~/logic/api/global';
|
|||||||
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
|
||||||
import useLocalState from '~/logic/state/local';
|
import useLocalState from '~/logic/state/local';
|
||||||
|
|
||||||
const TruncText = styled(Box)`
|
const TruncText = styled(Text)`
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Participant = Contact & { patp: string; pending: boolean };
|
type Participant = Contact & { patp: string; pending: boolean };
|
||||||
@ -55,8 +57,10 @@ function getParticipants(cs: Contacts, group: Group) {
|
|||||||
patp,
|
patp,
|
||||||
pending: false
|
pending: false
|
||||||
}));
|
}));
|
||||||
const members: Participant[] = _.map(Array.from(group.members), m =>
|
const members: Participant[] = _.map(
|
||||||
emptyContact(m, false)
|
Array.from(group.members)
|
||||||
|
.filter(e => group?.policy?.invite?.pending ? !group.policy.invite.pending.has(e) : true), m =>
|
||||||
|
emptyContact(m, false)
|
||||||
);
|
);
|
||||||
const allMembers = _.unionBy(contacts, members, 'patp');
|
const allMembers = _.unionBy(contacts, members, 'patp');
|
||||||
const pending: Participant[] =
|
const pending: Participant[] =
|
||||||
@ -303,11 +307,13 @@ function Participant(props: {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box>{avatar}</Box>
|
<Box>{avatar}</Box>
|
||||||
<Col justifyContent="center" gapY="1" height="100%">
|
<Col justifyContent="center" gapY="1" height="100%" minWidth='0'>
|
||||||
{hasNickname && (
|
{hasNickname && (
|
||||||
<TruncText title={contact.nickname} maxWidth="85%" color="black">
|
<Row minWidth='0' flexShrink='1'>
|
||||||
|
<TruncText title={contact.nickname} color="black">
|
||||||
{contact.nickname}
|
{contact.nickname}
|
||||||
</TruncText>
|
</TruncText>
|
||||||
|
</Row>
|
||||||
)}
|
)}
|
||||||
<Text title={contact.patp} color="gray" fontFamily="mono">
|
<Text title={contact.patp} color="gray" fontFamily="mono">
|
||||||
{cite(contact.patp)}
|
{cite(contact.patp)}
|
||||||
|
Loading…
Reference in New Issue
Block a user