interface: buggy implementation of reply view

This commit is contained in:
Logan Allen 2021-03-22 17:20:55 -05:00
parent de14c5d8a1
commit 4650f507e2
9 changed files with 260 additions and 55 deletions

View File

@ -20,7 +20,6 @@ interface AuthorProps {
showImage?: boolean;
children?: ReactNode;
unread?: boolean;
group: Group;
api?: GlobalApi;
size?: number;
}
@ -109,7 +108,10 @@ export default function Author(props: AuthorProps): ReactElement {
return (
<Row alignItems='center' width='auto'>
<Box
onClick={() => toggleOverlay()}
onClick={(e) => {
e.stopPropagation();
toggleOverlay();
}}
height={size}
position='relative'
cursor='pointer'
@ -120,7 +122,6 @@ export default function Author(props: AuthorProps): ReactElement {
ship={ship}
contact={contact}
color={`#${uxToHex(contact?.color ?? '0x0')}`}
group={group}
onDismiss={() => toggleOverlay()}
history={history}
className='relative'

View File

@ -1,13 +1,13 @@
import React, {
useEffect
} from 'react';
import { Box, Row, Text } from '@tlon/indigo-react'
import { GroupFeedHeader } from './GroupFeedHeader';
import { PostInput } from './Post/PostInput';
import { PostFeed } from './Post/PostFeed';
import { Loading } from '~/views/components/Loading';
import { Switch, Route } from 'react-router-dom';
import { Box } from '@tlon/indigo-react'
import { resourceFromPath } from '~/logic/lib/group';
import useGraphState from '~/logic/state/graph';
import { GroupFeedHeader } from './GroupFeedHeader';
import { PostTimeline } from './Post/PostTimeline';
import { PostReplies } from './Post/PostReplies';
export function GroupFeed(props) {
@ -16,16 +16,12 @@ export function GroupFeed(props) {
api,
history,
associations,
groups,
contacts,
graphPath
} = props;
const graphResource = resourceFromPath(graphPath);
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const graphs = useGraphState(state => state.graphs);
const pendingSize = useGraphState(state => state.pendingSize);
const shouldRenderFeed = graphId in graphs;
const graphResource = resourceFromPath(graphPath);
const relativePath = (path) => baseUrl + path;
useEffect(() => {
// TODO: VirtualScroller should support lower starting values than 100
@ -41,36 +37,31 @@ export function GroupFeed(props) {
alignItems="center"
overflow="hidden">
<GroupFeedHeader baseUrl={baseUrl} history={history} />
<Box
width="100%"
maxWidth="616px"
pt="3"
pl="2"
pr="2"
mb="3"
flexDirection="column"
alignItems="center">
{ shouldRenderFeed ? (
<PostInput api={api} graphResource={graphResource} />
) : null
}
</Box>
<Box height="calc(100% - 136px)" width="100%" alignItems="center" pl="1">
{ shouldRenderFeed ? (
<PostFeed
graphResource={graphResource}
graph={graphs[graphId]}
pendingSize={pendingSize}
associations={associations}
groups={groups}
contacts={contacts}
api={api}
history={history}
baseUrl={baseUrl}
/>
) : <Loading />
}
</Box>
<Switch>
<Route
exact
path={[relativePath('/'), relativePath('/feed')]}
render={(routeProps) => {
return (
<PostTimeline
{...props}
graphs={graphs}
pendingSize={pendingSize}
graphResource={graphResource} />
);
}} />
<Route
path={relativePath('/feed/:index+')}
render={(routeProps) => {
return (
<PostReplies
{...props}
graphs={graphs}
pendingSize={pendingSize}
graphResource={graphResource} />
);
}} />
</Switch>
</Box>
);
}

View File

@ -1,6 +1,9 @@
import React from 'react';
import bigInt from 'big-integer';
import VirtualScroller from "~/views/components/VirtualScroller";
import PostItem from './PostItem';
import { Col } from '@tlon/indigo-react';
const virtualScrollerStyle = {
height: "100%"
@ -13,10 +16,63 @@ export class PostFeed extends React.Component {
this.isFetching = false;
this.renderItem = React.forwardRef(({ index, scrollWindow }, ref) => {
const { graph, graphResource, contacts, api, history, baseUrl } = this.props;
const {
graph,
graphResource,
contacts,
api,
history,
baseUrl,
parentNode
} = this.props;
const node = graph.get(index);
if (!node) { return null; }
const first = graph.peekLargest()?.[0];
const post = node?.post;
if (!node || !post) {
return null;
}
if (parentNode && index.eq(first ?? bigInt.zero)) {
return (
<React.Fragment key={index.toString()}>
<Col
key={index.toString()}
mb="3"
width="100%"
flexShrink={0}
>
<PostItem
key={parentNode.post.index}
ref={ref}
node={parentNode}
contacts={contacts}
graphResource={graphResource}
api={api}
index={bigInt(parentNode.post.index.slice(1))}
baseUrl={baseUrl}
history={history}
isParent={true}
/>
</Col>
<PostItem
key={index.toString()}
ref={ref}
node={node}
contacts={contacts}
graphResource={graphResource}
api={api}
index={index}
baseUrl={baseUrl}
history={history}
isReply={true}
parentPost={parentNode.post}
/>
</React.Fragment>
);
}
return (
<PostItem
key={index.toString()}
@ -28,6 +84,8 @@ export class PostFeed extends React.Component {
index={index}
baseUrl={baseUrl}
history={history}
parentPost={parentNode?.post}
isReply={!!parentNode}
/>
);
});

View File

@ -7,7 +7,10 @@ export function PostFooter(props) {
return (
<Row mt={2} justify-content="flex-start">
<Row cursor="pointer" onClick={toggleReplyMode}>
<Row cursor="pointer" onClick={(e) => {
e.stopPropagation();
toggleReplyMode();
}}>
<Icon icon="Chat" />
{ replyCount > 0 ? (
<Text pl="1" gray>{replyCount}</Text>

View File

@ -4,10 +4,11 @@ import Author from '~/views/components/Author';
export function PostHeader(props) {
const { post, contacts, api} = props;
const { post, contacts, api, isReply } = props;
const mb = isReply ? "2" : "3";
return (
<Row width="100%" height="36px" mb={3} justifyContent="space-between">
<Row width="100%" height="36px" mb={mb} justifyContent="space-between">
<Author
showImage
contacts={contacts}

View File

@ -1,9 +1,10 @@
import React from 'react';
import { Box, Col } from '@tlon/indigo-react';
import { Box, Col, Row, Text } from '@tlon/indigo-react';
import { PostHeader } from './PostHeader';
import { PostContent } from './PostContent';
import { PostFooter } from './PostFooter';
import { PostInput } from './PostInput';
import { Mention } from "~/views/components/MentionText";
class PostItem extends React.Component {
@ -23,7 +24,7 @@ class PostItem extends React.Component {
navigateToReplies() {
const { history, baseUrl, index } = this.props;
//history.push(`${baseUrl}/feed/${index.toString()}`);
history.push(`${baseUrl}/feed/${index.toString()}`);
}
submitCallback() {
@ -32,7 +33,17 @@ class PostItem extends React.Component {
}
render() {
const { node, contacts, api, graphResource, index, innerRef } = this.props;
const {
node,
contacts,
api,
graphResource,
index,
innerRef,
isParent,
isReply,
parentPost
} = this.props;
const { inReplyMode } = this.state;
return (
@ -46,12 +57,19 @@ class PostItem extends React.Component {
<Col
p="2"
border={1}
borderColor="lightGray"
borderColor={ isParent ? "gray" : "lightGray" }
borderRadius="2"
width="100%"
maxWidth="600px"
onClick={this.navigateToReplies}>
<PostHeader post={node.post} contacts={contacts} api={api} />
onClick={this.navigateToReplies}
cursor="pointer">
<PostHeader post={node.post} contacts={contacts} api={api} isReply={isReply} />
{ isReply ? (
<Row width="100%" alignItems="center" mb="3">
<Text color="gray" pr="1">Replying to</Text>
<Mention ship={parentPost.author} />
</Row>
) : null }
<PostContent
post={node.post}
contacts={contacts} />

View File

@ -0,0 +1,74 @@
import React from 'react';
import bigInt from 'big-integer';
import { Box } from '@tlon/indigo-react'
import { PostInput } from './PostInput';
import { PostFeed } from './PostFeed';
import { Loading } from '~/views/components/Loading';
export function PostReplies(props) {
const {
baseUrl,
api,
history,
associations,
groups,
contacts,
graphPath,
graphs,
pendingSize,
graphResource
} = props;
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const shouldRenderFeed = graphId in graphs;
if (!shouldRenderFeed) {
return (
<Box height="100%" width="100%" alignItems="center" pl="1" pt="3">
<Loading />
</Box>
);
}
const locationUrl =
history.location.pathname.replace(`${baseUrl}/feed`, '');
console.log(locationUrl);
let nodeIndex = locationUrl.split('/').slice(1).map((ind) => {
return bigInt(ind);
});
let node;
let graph = graphs[graphId];
nodeIndex.forEach((i) => {
if (!graph) {
return null;
}
node = graph.get(i);
if (!node) {
return null;
}
graph = node.children;
});
if (!node || !graph) {
return null;
}
return (
<Box height="100%" width="100%" alignItems="center" pl="1" pt="3">
<PostFeed
graphResource={graphResource}
graph={graph}
parentNode={node}
pendingSize={pendingSize}
associations={associations}
groups={groups}
contacts={contacts}
api={api}
history={history}
baseUrl={baseUrl}
/>
</Box>
);
}

View File

@ -0,0 +1,59 @@
import React from 'react';
import { Box } from '@tlon/indigo-react'
import { PostInput } from './PostInput';
import { PostFeed } from './PostFeed';
import { Loading } from '~/views/components/Loading';
export function PostTimeline(props) {
const {
baseUrl,
api,
history,
associations,
groups,
contacts,
graphPath,
graphs,
pendingSize,
graphResource
} = props;
const graphId = `${graphResource.ship.slice(1)}/${graphResource.name}`;
const shouldRenderFeed = graphId in graphs;
return (
<>
<Box
width="100%"
maxWidth="616px"
pt="3"
pl="2"
pr="2"
mb="3"
flexDirection="column"
alignItems="center">
{ shouldRenderFeed ? (
<PostInput api={api} graphResource={graphResource} />
) : null
}
</Box>
<Box height="calc(100% - 136px)" width="100%" alignItems="center" pl="1">
{ shouldRenderFeed ? (
<PostFeed
graphResource={graphResource}
graph={graphs[graphId]}
pendingSize={pendingSize}
associations={associations}
groups={groups}
contacts={contacts}
api={api}
history={history}
baseUrl={baseUrl}
/>
) : <Loading />
}
</Box>
</>
);
}

View File

@ -73,7 +73,7 @@ export function SidebarListHeader(props: {
borderColor="washedGray"
backgroundColor={['transparent',
props.history.location.pathname === `/~landscape${groupPath}` ||
props.history.location.pathname === `/~landscape${groupPath}/feed`
props.history.location.pathname.includes(`/~landscape${groupPath}/feed`)
? (
'washedGray'
) : (