chat: improve multicontent rendering

This commit is contained in:
Liam Fitzgerald 2020-12-07 14:35:10 +10:00
parent b516926510
commit e7de3533ee
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
6 changed files with 80 additions and 27 deletions

View File

@ -11,6 +11,7 @@ import TextContent from './content/text';
import CodeContent from './content/code';
import RemoteContent from '~/views/components/RemoteContent';
import { Mention } from "~/views/components/MentionText";
import styled from "styled-components";
export const DATESTAMP_FORMAT = '[~]YYYY.M.D';
@ -251,7 +252,7 @@ export class MessageWithSigil extends PureComponent<MessageProps> {
<Text flexShrink='0' gray mono className="v-mid">{timestamp}</Text>
<Text flexShrink={0} gray mono ml={2} className="v-mid child dn-s">{datestamp}</Text>
</Box>
<Box flexShrink={0} fontSize={fontSize ? fontSize : '14px'}>
<ContentBox flexShrink={0} fontSize={fontSize ? fontSize : '14px'}>
{msg.contents.map(c =>
<MessageContent
contacts={contacts}
@ -260,19 +261,26 @@ export class MessageWithSigil extends PureComponent<MessageProps> {
measure={measure}
fontSize={fontSize}
/>)}
</Box>
</ContentBox>
</Box>
</>
);
}
}
const ContentBox = styled(Box)`
& > :first-child {
margin-left: 0px;
}
`;
export const MessageWithoutSigil = ({ timestamp, contacts, msg, remoteContentPolicy, measure }) => (
<>
<Text flexShrink={0} mono gray display='inline-block' pt='2px' lineHeight='tall' className="child">{timestamp}</Text>
<Box flexShrink={0} fontSize='14px' className="clamp-message" style={{ flexGrow: 1 }}>
<ContentBox flexShrink={0} fontSize='14px' className="clamp-message" style={{ flexGrow: 1 }}>
{msg.contents.map(c => (<MessageContent contacts={contacts} content={c} remoteContentPolicy={remoteContentPolicy} measure={measure}/>))}
</Box>
</ContentBox>
</>
);
@ -281,7 +289,7 @@ export const MessageContent = ({ content, contacts, remoteContentPolicy, measure
return <CodeContent content={content} />;
} else if ('url' in content) {
return (
<Text flexShrink={0} fontSize={fontSize ? fontSize : '14px'} lineHeight="tall" color='black'>
<Text mx="2px" flexShrink={0} fontSize={fontSize ? fontSize : '14px'} lineHeight="tall" color='black'>
<RemoteContent
url={content.url}
remoteContentPolicy={remoteContentPolicy}

View File

@ -261,7 +261,6 @@ export default class ChatWindow extends Component<ChatWindowProps, ChatWindowSta
const unreadMarkerRef = this.unreadMarkerRef;
let lastMessage = 0;
const messageProps = { association, group, contacts, hideAvatars, hideNicknames, remoteContentPolicy, unreadMarkerRef, history, api };
@ -297,7 +296,7 @@ export default class ChatWindow extends Component<ChatWindowProps, ChatWindowSta
return <MessagePlaceholder key={index.toString()} height="64px" index={index} />;
}
const isPending: boolean = 'pending' in msg && Boolean(msg.pending);
const isLastMessage: boolean = Boolean(index.eq(bigInt(lastMessage)));
const isLastMessage = index.eq(graph.peekLargest()?.[0] ?? bigInt.zero);
const highlighted = bigInt(this.props.scrollTo || -1).eq(index);
const graphIdx = keys.findIndex(idx => idx.eq(index));
const prevIdx = keys[graphIdx+1];

View File

@ -86,7 +86,7 @@ export default class TextContent extends Component {
&& (urbitOb.isValidPatp(group[2]) // valid patp?
&& (group[0] === content.text))) { // entire message is room name?
return (
<Text flexShrink={0} fontSize={props.fontSize ? props.fontSize : '14px'} color='black' lineHeight="tall">
<Text mx="2px" flexShrink={0} fontSize={props.fontSize ? props.fontSize : '14px'} color='black' lineHeight="tall">
<Link
className="bb b--black b--white-d mono"
to={'/~landscape/join/' + group.input}>
@ -96,7 +96,7 @@ export default class TextContent extends Component {
);
} else {
return (
<Text flexShrink={0} color='black' fontSize={props.fontSize ? props.fontSize : '14px'} lineHeight="tall" style={{ overflowWrap: 'break-word' }}>
<Text mx="2px" flexShrink={0} color='black' fontSize={props.fontSize ? props.fontSize : '14px'} lineHeight="tall" style={{ overflowWrap: 'break-word' }}>
<MessageMarkdown source={content.text} />
</Text>
);

View File

@ -1,9 +1,16 @@
import React from "react";
import React, { useState, useCallback } from "react";
import _ from "lodash";
import { Text } from "@tlon/indigo-react";
import { Contacts, Content, LocalUpdateRemoteContentPolicy } from "~/types";
import { Text, Box } from "@tlon/indigo-react";
import {
Contacts,
Content,
LocalUpdateRemoteContentPolicy,
Group,
} from "~/types";
import RichText from "~/views/components/RichText";
import { cite } from "~/logic/lib/util";
import { cite, uxToHex } from "~/logic/lib/util";
import { ProfileOverlay } from "./ProfileOverlay";
import {useHistory} from "react-router-dom";
interface MentionTextProps {
contacts: Contacts;
@ -37,15 +44,54 @@ export function MentionText(props: MentionTextProps) {
);
}
export function Mention(props: { ship: string; contacts: Contacts }) {
export function Mention(props: {
ship: string;
contacts: Contacts;
group: Group;
}) {
const { contacts, ship } = props;
const contact = contacts[ship];
const showNickname = !!contact?.nickname;
const name = showNickname ? contact?.nickname : cite(ship);
const [showOverlay, setShowOverlay] = useState(false);
const onDismiss = useCallback(() => {
setShowOverlay(false);
}, [setShowOverlay]);
const onClick = useCallback(() => {
setShowOverlay(true);
}, [setShowOverlay]);
const group = props.group ?? { hidden: true };
const history = useHistory();
return (
<Text mx="2px" px="2px" bg="washedBlue" color="blue" mono={!showNickname}>
{name}
</Text>
<Box
position="relative"
display="inline-block"
>
{showOverlay && (
<ProfileOverlay
ship={ship}
contact={contact}
color={uxToHex(contact?.color ?? '0x0')}
group={group}
onDismiss={onDismiss}
hideAvatars={false}
hideNicknames={false}
history={history}
/>
)}
<Text
onClick={onClick}
mx="2px"
px="2px"
bg="washedBlue"
color="blue"
mono={!showNickname}
>
{name}
</Text>
</Box>
);
}

View File

@ -80,7 +80,7 @@ export function ContactCard(props: ContactCardProps) {
const [,,ship] = props.path.split('/');
values.color = uxToHex(values.color);
const sharedValues = Object.assign({}, values);
sharedValues.avatar = (values.avatar === "") ? null : { url: values.avatar };
sharedValues.avatar = !values.avatar ? null : { url: values.avatar };
console.log(values);
await props.api.contacts.share(ship, props.path, us, sharedValues);
actions.setStatus({ success: null });

View File

@ -1,4 +1,4 @@
import React, { Component, useEffect } from 'react';
import React, { Component, useEffect, useCallback } from 'react';
import { Route, Switch, RouteComponentProps } from 'react-router-dom';
import './css/custom.css';
@ -25,18 +25,21 @@ type LandscapeProps = StoreState & {
export function DMRedirect(props: LandscapeProps & RouteComponentProps & { ship: string; }) {
const { ship, api, history, graphKeys } = props;
const goToGraph = useCallback((graph: string) => {
history.push(`/~landscape/home/resource/chat/ship/~${graph}`);
}, [history]);
useEffect(() => {
const station = `/ship/~${window.ship}/dm--${ship}`;
const theirStation = `/ship/~${ship}/dm--${window.ship}`;
const station = `${window.ship}/dm--${ship}`;
const theirStation = `${ship}/dm--${window.ship}`;
if (graphKeys.has(station)) {
history.push(`/~landscape/home/resource/chat${station}`);
goToGraph(station);
return;
}
if (graphKeys.has(theirStation)) {
history.push(`/~landscape/home/resource/chat${theirStation}`);
goToGraph(theirStation);
return;
}
@ -51,7 +54,7 @@ export function DMRedirect(props: LandscapeProps & RouteComponentProps & { ship:
{ invite: { pending: aud } },
'chat'
).then(() => {
history.push(`/~landscape/home/resource/chat${station}`);
goToGraph(station);
});
}, []);
@ -70,9 +73,6 @@ export default class Landscape extends Component<LandscapeProps, {}> {
this.props.subscription.startApp('graph');
}
createandRedirectToDM(api, ship, history, allStations) {
}
render() {
const { props } = this;
const { api } = props;