ChatMessage: refactor content rendering

This commit is contained in:
Liam Fitzgerald 2021-04-07 13:14:33 +10:00
parent 186ac17d5d
commit 156f91adb5
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
6 changed files with 119 additions and 133 deletions

View File

@ -29,8 +29,8 @@ import {
Groups,
Associations
} from '~/types';
import TextContent from './content/text';
import CodeContent from './content/code';
import TextContent from '../../../landscape/components/Graph/content/text';
import CodeContent from '../../../landscape/components/Graph/content/code';
import RemoteContent from '~/views/components/RemoteContent';
import { Mention } from '~/views/components/MentionText';
import { Dropdown } from '~/views/components/Dropdown';
@ -42,8 +42,7 @@ import useContactState from '~/logic/state/contact';
import { useIdlingState } from '~/logic/lib/idling';
import ProfileOverlay from '~/views/components/ProfileOverlay';
import {useCopy} from '~/logic/lib/useCopy';
import {PermalinkEmbed} from '../../permalinks/embed';
import {referenceToPermalink} from '~/logic/lib/permalinks';
import {GraphContentWide} from '~/views/landscape/components/Graph/GraphContentWide';
export const DATESTAMP_FORMAT = '[~]YYYY.M.D';
@ -396,12 +395,11 @@ export const MessageAuthor = ({
msg.author !== window.ship) &&
`~${msg.author}` in contacts
? contacts[`~${msg.author}`]
: false;
: undefined;
const showNickname = useShowNickname(contact);
const { hideAvatars } = useSettingsState(selectCalmState);
const shipName = showNickname ? contact.nickname : cite(msg.author);
const copyNotice = 'Copied';
const shipName = showNickname && contact?.nickname || cite(msg.author) || `~${msg.author}`;
const color = contact
? `#${uxToHex(contact.color)}`
: dark
@ -412,28 +410,10 @@ export const MessageAuthor = ({
: dark
? 'mix-blend-diff'
: 'mix-blend-darken';
const [displayName, setDisplayName] = useState(shipName);
const [nameMono, setNameMono] = useState(showNickname ? false : true);
const { copyDisplay, doCopy, didCopy } = useCopy(`~${msg.author}`, shipName);
const { hovering, bind } = useHovering();
const [showOverlay, setShowOverlay] = useState(false);
const toggleOverlay = () => {
setShowOverlay((value) => !value);
};
const showCopyNotice = () => {
setDisplayName(copyNotice);
setNameMono(false);
};
useEffect(() => {
const resetDisplay = () => {
setDisplayName(shipName);
setNameMono(showNickname ? false : true);
};
const timer = setTimeout(() => resetDisplay(), 800);
return () => clearTimeout(timer);
}, [shipName, displayName]);
const nameMono = !(showNickname || didCopy);
const img =
contact?.avatar && !hideAvatars ? (
@ -470,10 +450,7 @@ export const MessageAuthor = ({
return (
<Box display='flex' alignItems='flex-start' {...rest}>
<Box
onClick={() => {
setShowOverlay(true);
}}
height={24}
height={24}
pr={2}
mt={'1px'}
pl={'12px'}
@ -500,13 +477,10 @@ export const MessageAuthor = ({
mono={nameMono}
fontWeight={nameMono ? '400' : '500'}
cursor='pointer'
onClick={() => {
writeText(`~${msg.author}`);
showCopyNotice();
}}
onClick={doCopy}
title={`~${msg.author}`}
>
{displayName}
{copyDisplay}
</Text>
<Text flexShrink={0} fontSize={0} gray>
{timestamp}
@ -538,7 +512,6 @@ export const Message = ({
...rest
}) => {
const { hovering, bind } = useHovering();
const contacts = useContactState((state) => state.contacts);
return (
<Box width="100%" position='relative' {...rest}>
{timestampHover ? (
@ -557,66 +530,14 @@ export const Message = ({
) : (
<></>
)}
<Box width="100%" {...bind}>
{msg.contents.map((content, i) => {
switch (Object.keys(content)[0]) {
case 'text':
return (
<TextContent
key={i}
api={api}
fontSize={1}
lineHeight={'20px'}
content={content}
/>
);
case 'code':
return <CodeContent key={i} content={content} />;
case 'reference':
const { link } = referenceToPermalink(content);
return (
<PermalinkEmbed
link={link}
api={api}
transcluded={transcluded}
showOurContact={showOurContact}
/>
);
case 'url':
return (
<Box
key={i}
flexShrink={0}
fontSize={1}
lineHeight='20px'
color='black'
width="fit-content"
maxWidth="500px"
>
<RemoteContent
key={content.url}
url={content.url}
/>
</Box>
);
case 'mention':
const first = (i) => i === 0;
return (
<Mention
key={i}
first={first(i)}
group={group}
scrollWindow={scrollWindow}
ship={content.mention}
contact={contacts?.[`~${content.mention}`]}
api={api}
/>
);
default:
return null;
}
})}
</Box>
<GraphContentWide
{...bind}
width="100%"
post={msg}
transcluded={transcluded}
api={api}
showOurContact={showOurContact}
/>
</Box>
);
};

View File

@ -6,7 +6,7 @@ import RichText from '~/views/components/RichText';
import { cite, useShowNickname, uxToHex } from '~/logic/lib/util';
import ProfileOverlay from '~/views/components/ProfileOverlay';
import { useHistory } from 'react-router-dom';
import useContactState from '~/logic/state/contact';
import useContactState, {useContact} from '~/logic/state/contact';
import {referenceToPermalink} from '~/logic/lib/permalinks';
import GlobalApi from '~/logic/api/global';
@ -40,46 +40,28 @@ export function MentionText(props: MentionTextProps) {
}
export function Mention(props: {
contact: Contact;
group: Group;
scrollWindow?: HTMLElement;
ship: string;
first?: Boolean;
api: any;
}) {
const { ship, scrollWindow, first, api, ...rest } = props;
let { contact } = props;
const contacts = useContactState(state => state.contacts);
contact = contact?.color ? contact : contacts?.[`~${ship}`];
const history = useHistory();
const { ship, first, api, ...rest } = props;
const contact = useContact(ship);
const showNickname = useShowNickname(contact);
const name = showNickname ? contact?.nickname : cite(ship);
const group = props.group ?? { hidden: true };
const [showOverlay, setShowOverlay] = useState(false);
const toggleOverlay = useCallback(() => {
setShowOverlay((value) => !value);
}, [showOverlay]);
return (
<Box position='relative' display='inline-block' cursor='pointer' {...rest}>
<ProfileOverlay
ship={ship}
api={api}
>
<Text
onClick={() => toggleOverlay()}
marginLeft={first? 0 : 1}
marginRight={1}
px={1}
bg='washedBlue'
color='blue'
fontSize={showNickname ? 1 : 0}
mono={!showNickname}
>
{name}
</Text>
</ProfileOverlay>
</Box>
<ProfileOverlay ship={ship} api={api}>
<Text
marginLeft={first? 0 : 1}
marginRight={1}
px={1}
bg='washedBlue'
color='blue'
fontSize={showNickname ? 1 : 0}
mono={!showNickname}
>
{name}
</Text>
</ProfileOverlay>
);
}

View File

@ -1,4 +1,4 @@
import React, { PureComponent, useCallback, useEffect, useRef, useState, useMemo } from 'react';
import React, { PureComponent, useCallback, useEffect, useRef, useState, useMemo, ReactNode } from 'react';
import { Contact, Group, uxToHex } from '@urbit/api';
import _ from 'lodash';
import VisibilitySensor from 'react-visibility-sensor';
@ -40,6 +40,7 @@ const FixedOverlay = styled(Col)`
type ProfileOverlayProps = BoxProps & {
ship: string;
api: any;
children: ReactNode;
};
const ProfileOverlay = (props: ProfileOverlayProps) => {

View File

@ -0,0 +1,82 @@
import React from "react";
import { Post, ReferenceContent } from "@urbit/api";
import { Box } from "@tlon/indigo-react";
import GlobalApi from "~/logic/api/global";
import TextContent from "./content/text";
import CodeContent from "./content/code";
import RemoteContent from "~/views/components/RemoteContent";
import { Mention } from "~/views/components/MentionText";
import { PermalinkEmbed } from "~/views/apps/permalinks/embed";
import { referenceToPermalink } from "~/logic/lib/permalinks";
import { PropFunc } from "~/types";
function GraphContentWideInner(
props: {
transcluded?: number;
post: Post;
api: GlobalApi;
showOurContact: boolean;
} & PropFunc<typeof Box>
) {
const { post, transcluded = 0, showOurContact, api, ...rest } = props;
return (
<Box {...rest}>
{post.contents.map((content, i) => {
switch (Object.keys(content)[0]) {
case "text":
return (
<TextContent
key={i}
api={api}
fontSize={1}
lineHeight={"20px"}
content={content}
/>
);
case "code":
return <CodeContent key={i} content={content} />;
case "reference":
const { link } = referenceToPermalink(content as ReferenceContent);
return (
<PermalinkEmbed
link={link}
api={api}
transcluded={transcluded}
showOurContact={showOurContact}
/>
);
case "url":
return (
<Box
key={i}
flexShrink={0}
fontSize={1}
lineHeight="20px"
color="black"
width="fit-content"
maxWidth="500px"
>
<RemoteContent key={content.url} url={content.url} />
</Box>
);
case "mention":
const first = (i) => i === 0;
return (
<Mention
key={i}
first={first(i)}
ship={content.mention}
api={api}
/>
);
default:
return null;
}
})}
</Box>
);
}
export const GraphContentWide = React.memo(GraphContentWideInner);