permalinks: cleanup styling

This commit is contained in:
Liam Fitzgerald 2021-03-22 12:51:30 +10:00
parent e49446f85e
commit 28a2aae408
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
13 changed files with 155 additions and 107 deletions

View File

@ -1,24 +1,23 @@
import { Association, resourceFromPath, Group } from "@urbit/api";
import { useGroupForAssoc } from "../state/group";
export function usePermalinkForGraph(assoc: Association, index = "") {
const group = useGroupForAssoc(assoc)!;
return getPermalinkForGraph(assoc, group, index);
}
import {
Association,
resourceFromPath,
Group,
ReferenceContent,
} from "@urbit/api";
export function getPermalinkForGraph(
assoc: Association,
group: Group,
group: string,
graph: string,
index = ""
) {
const groupLink = getPermalinkForAssociatedGroup(assoc, group);
const { ship, name } = resourceFromPath(assoc.resource);
const groupLink = getPermalinkForAssociatedGroup(group);
const { ship, name } = resourceFromPath(graph);
return `${groupLink}/graph/${ship}/${name}${index}`;
}
function getPermalinkForAssociatedGroup(assoc: Association, group: Group) {
const mod = assoc.metadata.module;
const { ship, name } = resourceFromPath(assoc.group);
function getPermalinkForAssociatedGroup(group: string) {
const { ship, name } = resourceFromPath(group);
return `web+urbit://group/${ship}/${name}`;
}

View File

@ -2,6 +2,7 @@ import React, { useRef, useCallback, useEffect, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Col } from '@tlon/indigo-react';
import _ from 'lodash';
import bigInt from 'big-integer';
import { Association } from '@urbit/api/metadata';
import { StoreState } from '~/logic/store/type';
@ -80,25 +81,17 @@ export function ChatResource(props: ChatResourceProps) {
const scrollTo = new URLSearchParams(location.search).get('msg');
useEffect(() => {
const clear = () => {
props.history.replace(location.pathname);
};
const timId = setTimeout(clear, 10000);
return () => {
clearTimeout(timId);
};
}, [station]);
const [showBanner, setShowBanner] = useState(false);
const [hasLoadedAllowed, setHasLoadedAllowed] = useState(false);
const [recipients, setRecipients] = useState([]);
const res = resourceFromPath(groupPath);
const onReply = useCallback((msg: Post) => {
const url = getPermalinkForGraph(props.association, group, msg.index)
const url = getPermalinkForGraph(
props.association.group,
props.association.resource,
msg.index
);
const message = `${url}\n~${msg.author} : `;
setUnsent(s => ({...s, [props.association.resource]: message }));
}, [props.association, group, setUnsent]);
@ -176,7 +169,7 @@ export function ChatResource(props: ChatResourceProps) {
onReply={onReply}
station={station}
api={props.api}
scrollTo={scrollTo ? parseInt(scrollTo, 10) : undefined}
scrollTo={scrollTo ? bigInt(scrollTo) : undefined}
/>
{ canWrite && (
<ChatInput

View File

@ -190,9 +190,11 @@ const MessageActions = ({ api, onReply, association, history, msg, group }) => {
Delete Message
</MessageActionItem>
) : null}
<MessageActionItem onClick={(e) => console.log(e)}>
View Signature
</MessageActionItem>
{false && (
<MessageActionItem onClick={(e) => console.log(e)}>
View Signature
</MessageActionItem>
)}
</Col>
}
>
@ -211,7 +213,10 @@ const MessageWrapper = (props) => {
return (
<Box
py='1'
backgroundColor={showHover ? 'washedGray' : 'transparent'}
backgroundColor={props.highlighted
? showHover ? 'lightBlue' : 'washedBlue'
: showHover ? 'washedGray' : 'transparent'
}
position='relative'
{...bind}
>
@ -326,9 +331,9 @@ class ChatMessage extends Component<ChatMessageProps> {
<Box
ref={this.props.innerRef}
pt={renderSigil ? 2 : 0}
width="100%"
pb={isLastMessage ? '20px' : 0}
className={containerClass}
backgroundColor={highlighted ? 'blue' : 'white'}
style={style}
>
{dayBreak && !isLastRead ? (
@ -543,7 +548,7 @@ export const Message = ({
const { hovering, bind } = useHovering();
const contacts = useContactState((state) => state.contacts);
return (
<Box position='relative' {...rest}>
<Box width="100%" position='relative' {...rest}>
{timestampHover ? (
<Text
display={hovering ? 'block' : 'none'}
@ -560,7 +565,7 @@ export const Message = ({
) : (
<></>
)}
<Box {...bind}>
<Box width="100%" {...bind}>
{msg.contents.map((content, i) => {
switch (Object.keys(content)[0]) {
case 'text':

View File

@ -41,7 +41,7 @@ type ChatWindowProps = RouteComponentProps<{
ship: Patp;
station: any;
api: GlobalApi;
scrollTo?: number;
scrollTo?: BigInteger;
onReply: (msg: Post) => void;
};
@ -88,10 +88,13 @@ class ChatWindow extends Component<
componentDidMount() {
this.calculateUnreadIndex();
setTimeout(() => {
if (this.props.scrollTo) {
this.scrollToUnread();
}
this.setState({ initialized: true });
this.setState({ initialized: true }, () => {
if(this.props.scrollTo) {
this.virtualList.scrollToIndex(this.props.scrollTo);
}
});
}, this.INITIALIZATION_MAX_TIME);
}
@ -243,7 +246,7 @@ class ChatWindow extends Component<
const isLastMessage = index.eq(
graph.peekLargest()?.[0] ?? bigInt.zero
);
const highlighted = false; // this.state.unreadIndex.eq(index);
const highlighted = index.eq(this.props.scrollTo ?? bigInt.zero);
const keys = graph.keys().reverse();
const graphIdx = keys.findIndex((idx) => idx.eq(index));
const prevIdx = keys[graphIdx + 1];

View File

@ -82,7 +82,7 @@ export function LinkResource(props: LinkResourceProps) {
}}
/>
<Route
path={relativePath('/:index')}
path={relativePath('/index/:index')}
render={(props) => {
const index = bigInt(props.match.params.index);
const editCommentId = props.match.params.commentId || null;

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef, useCallback, ReactElement } from '
import { Link } from 'react-router-dom';
import { Row, Col, Anchor, Box, Text, Icon, Action } from '@tlon/indigo-react';
import { GraphNode, Group, Rolodex, Unreads } from '@urbit/api';
import { GraphNode, Group, Rolodex, Unreads, Association } from '@urbit/api';
import { writeText } from '~/logic/lib/util';
import Author from '~/views/components/Author';
@ -12,18 +12,15 @@ import { Dropdown } from '~/views/components/Dropdown';
import RemoteContent from '~/views/components/RemoteContent';
import useHarkState from '~/logic/state/hark';
import {useCopy} from '~/logic/lib/useCopy';
import {usePermalinkForGraph} from '~/logic/lib/permalinks';
import {usePermalinkForGraph, getPermalinkForGraph} from '~/logic/lib/permalinks';
interface LinkItemProps {
node: GraphNode;
resource: string;
api: GlobalApi;
group: Group;
path: string;
}
export const LinkItem = (props: LinkItemProps): ReactElement => {
association: Association;
resource: string; api: GlobalApi; group: Group; path: string; }
export const LinkItem = (props: LinkItemProps): ReactElement => {
const {
association,
node,
resource,
api,
@ -34,10 +31,11 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
const ref = useRef<HTMLDivElement | null>(null);
const remoteRef = useRef<typeof RemoteContent | null>(null);
const index = node.post.index.split('/')[1];
const markRead = useCallback(() => {
api.hark.markEachAsRead(props.association, '/', `/${index}`, 'link', 'link');
}, [props.association, index]);
}, [association, index]);
useEffect(() => {
function onBlur() {
@ -61,7 +59,6 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
);
const author = node.post.author;
const index = node.post.index.split('/')[1];
const size = node.children ? node.children.size : 0;
const contents = node.post.contents;
const hostname = URLparser.exec(contents[1].url) ? URLparser.exec(contents[1].url)[4] : null;
@ -73,7 +70,11 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
const [ship, name] = resource.split('/');
const permalink = usePermalinkForGraph(props.association, node.post.index);
const permalink = getPermalinkForGraph(
association.group,
association.resource,
`/${index}`
);
const { doCopy: doCopyLink, copyDisplay: locationText } = useCopy(
contents[1].url,
@ -161,7 +162,7 @@ export const LinkItem = (props: LinkItemProps): ReactElement => {
/>
<Box ml="auto">
<Link
to={node.post.pending ? '#' : `${baseUrl}/${index}`}
to={node.post.pending ? '#' : `${baseUrl}/index/${index}`}
style={{ cursor: node.post.pending ? 'default' : 'pointer' }}>
<Box display='flex'>
<Icon color={commColor} icon='Chat' />

View File

@ -20,6 +20,7 @@ import { MentionText } from '~/views/components/MentionText';
import ChatMessage from '../chat/components/ChatMessage';
import useContactState from '~/logic/state/contact';
import useGroupState from '~/logic/state/group';
import useMetadataState from '~/logic/state/metadata';
function getGraphModuleIcon(module: string) {
if (module === 'link') {
@ -68,6 +69,7 @@ const GraphUrl = ({ url, title }) => (
export const GraphNodeContent = ({
group,
association,
post,
mod,
index,
@ -130,6 +132,7 @@ export const GraphNodeContent = ({
containerClass='items-top cf hide-child'
group={group}
groups={{}}
association={association}
associations={{ graph: {}, groups: {} }}
msg={post}
fontSize='0'
@ -163,6 +166,9 @@ function getNodeUrl(
const [linkId] = idx;
return `${graphUrl}/${linkId}`;
} else if (mod === 'chat') {
if(idx.length > 0) {
return `${graphUrl}?msg=${idx[0]}`;
}
return graphUrl;
}
return '';
@ -186,6 +192,9 @@ const GraphNode = ({
const contacts = useContactState((state) => state.contacts);
const nodeUrl = getNodeUrl(mod, group?.hidden, groupPath, graph, index);
const association = useMetadataState(
useCallback(s => s.associations.graph[graph], [graph])
);
const onClick = useCallback(() => {
if (!read) {
@ -194,11 +203,6 @@ const GraphNode = ({
history.push(nodeUrl);
}, [read, onRead]);
const showNickname = useShowNickname(contacts?.[`~${author}`]);
const nickname =
contacts?.[`~${author}`]?.nickname && showNickname
? contacts[`~${author}`].nickname
: cite(author);
return (
<Row onClick={onClick} gapX='2' pt={showContact ? 2 : 0}>
<Col flexGrow={1} alignItems='flex-start'>
@ -210,6 +214,7 @@ const GraphNode = ({
post={post}
mod={mod}
description={description}
association={association}
index={index}
group={group}
remoteContentPolicy={{}}

View File

@ -91,9 +91,9 @@ function TranscludedPublishNode(props: {
?.get(bigInt.one)
?.children?.peekLargest()?.[1]!;
return (
<Col>
<Col gapY="2">
<Author
p="2"
px="2"
showImage
ship={post.post.author}
date={post.post?.["time-sent"]}
@ -128,6 +128,7 @@ export function TranscludedNode(props: {
assoc: Association;
node: GraphNode;
transcluded: number;
api: GlobalApi;
}) {
const { node, assoc, transcluded } = props;
const group = useGroupForAssoc(assoc)!;
@ -136,6 +137,7 @@ export function TranscludedNode(props: {
return (
<Row width="100%" flexShrink={0} flexGrow={1} flexWrap="wrap">
<ChatMessage
width="100%"
renderSigil
transcluded={transcluded + 1}
containerClass="items-top cf hide-child"

View File

@ -2,6 +2,8 @@ import React, { useCallback, useEffect, useState } from "react";
import {
parsePermalink,
GraphPermalink as IGraphPermalink,
getPermalinkForGraph,
usePermalinkForGraph,
} from "~/logic/lib/permalinks";
import {
Action,
@ -71,7 +73,54 @@ function GraphPermalink(
})();
}, [pending, graph, index]);
const showTransclusion = !!(association && node && transcluded < 1);
const permalink = getPermalinkForGraph(group, graph, index);
return (
<Col
width="100%"
my="1"
bg="white"
border="1"
borderColor="lightGray"
borderRadius="2"
>
{showTransclusion && (
<Box p="2">
<TranscludedNode
api={api}
transcluded={transcluded + 1}
node={node}
assoc={association!}
/>
</Box>
)}
{!!association ? (
<PermalinkDetails
known
showTransclusion={showTransclusion}
icon={getModuleIcon(association.metadata.module)}
title={association.metadata.title}
permalink={permalink}
/>
) : (
<PermalinkDetails
icon="Groups"
title={graph.slice(5)}
permalink={permalink}
/>
)}
</Col>
);
}
function PermalinkDetails(props: {
title: string;
icon: any;
permalink: string;
showTransclusion?: boolean;
known?: boolean;
}) {
const { title, icon, permalink, known, showTransclusion } = props;
const rowTransclusionStyle = showTransclusion
? {
borderTop: "1",
@ -81,39 +130,24 @@ function GraphPermalink(
: {};
return (
<Col my="1" bg="white" border="1" borderColor="lightGray" borderRadius="2">
{showTransclusion && (
<Box p="2">
<TranscludedNode
transcluded={transcluded + 1}
node={node}
assoc={association!}
/>
</Box>
)}
<Row
{...rowTransclusionStyle}
alignItems="center"
justifyContent="space-between"
width="100%"
px="2"
py="1"
>
<Row gapX="2" alignItems="center">
<Icon
icon={
association
? (getModuleIcon(association.metadata.module) as any)
: "Groups"
}
/>
<Text lineHeight="20px" mono={!association}>
{association?.metadata.title ?? graph.slice(6)}
</Text>
</Row>
<Action onClick={() => {}}>Go to link</Action>
<Row
{...rowTransclusionStyle}
alignItems="center"
justifyContent="space-between"
width="100%"
px="2"
py="1"
>
<Row gapX="2" alignItems="center">
<Icon icon={icon} />
<Text lineHeight="20px" mono={!known}>
{title}
</Text>
</Row>
</Col>
<Link to={`/perma${permalink.slice(11)}`}>
<Text color="blue">Go to link</Text>
</Link>
</Row>
);
}

View File

@ -64,7 +64,7 @@ function getLinkPermalink(
(acc, val, i) => {
console.log(acc);
if (i === 0) {
return {...acc, pathname: `${acc.pathname}/${val}` };
return {...acc, pathname: `${acc.pathname}/index/${val}` };
} else if (i === 1) {
return {...acc, search: `?selected=${val}` };
}

View File

@ -13,7 +13,8 @@ import { roleForShip } from '~/logic/lib/group';
import Author from '~/views/components/Author';
import { Contacts, GraphNode, Graph, Association, Unreads, Group } from '@urbit/api';
import {useCopy} from '~/logic/lib/useCopy';
import {usePermalinkForGraph} from '~/logic/lib/permalinks';
import {usePermalinkForGraph, getPermalinkForGraph} from '~/logic/lib/permalinks';
import {useQuery} from '~/logic/lib/useQuery';
interface NoteProps {
ship: string;
@ -48,8 +49,7 @@ export function NoteContent({ body }) {
export function Note(props: NoteProps & RouteComponentProps) {
const [deleting, setDeleting] = useState(false);
const { notebook, note, ship, book, api, rootUrl, baseUrl, group } = props;
const editCommentId = props.match.params.commentId;
const { association, notebook, note, ship, book, api, rootUrl, baseUrl, group } = props;
const deletePost = async () => {
setDeleting(true);
@ -58,6 +58,7 @@ export function Note(props: NoteProps & RouteComponentProps) {
props.history.push(rootUrl);
};
const { query } = useQuery();
const comments = getComments(note);
const [revNum, title, body, post] = getLatestRevision(note);
const index = note.post.index.split('/');
@ -85,16 +86,20 @@ export function Note(props: NoteProps & RouteComponentProps) {
)
};
const permalink = usePermalinkForGraph(props.association, `/${noteId.toString()}`)
const permalink = getPermalinkForGraph(
association.group,
association.resource,
`/${noteId.toString()}`
);
const { doCopy, copyDisplay } = useCopy(permalink, 'Copy Link');
const windowRef = React.useRef(null);
useEffect(() => {
if (windowRef.current) {
if (windowRef.current && !query.has('selected')) {
windowRef.current.parentElement.scrollTop = 0;
}
}, [windowRef, note]);
}, [note, windowRef]);
return (
<Box
@ -142,7 +147,6 @@ export function Note(props: NoteProps & RouteComponentProps) {
association={props.association}
api={props.api}
baseUrl={baseUrl}
editCommentId={editCommentId}
history={props.history}
group={group}
/>

View File

@ -13,7 +13,7 @@ import { MentionText } from '~/views/components/MentionText';
import { roleForShip } from '~/logic/lib/group';
import { getLatestCommentRevision } from '~/logic/lib/publish';
import {useCopy} from '~/logic/lib/useCopy';
import {usePermalinkForGraph} from '~/logic/lib/permalinks';
import { getPermalinkForGraph} from '~/logic/lib/permalinks';
import useMetadataState from '~/logic/state/metadata';
const ClickBox = styled(Box)`
@ -71,14 +71,17 @@ export function CommentItem(props: CommentItemProps): ReactElement {
useEffect(() => {
if(ref.current && props.highlighted) {
ref.current.scrollIntoView();
ref.current.scrollIntoView({ block: 'center' });
}
}, [ref, props.highlighted]);
const history = useHistory();
const { copyDisplay, doCopy } = useCopy(
usePermalinkForGraph(association, post.index.split('/').slice(0, -1).join('/')),
getPermalinkForGraph(
association.group,
association.resource,
post.index.split('/').slice(0, -1).join('/')
),
'Copy Link'
);
@ -102,7 +105,7 @@ export function CommentItem(props: CommentItemProps): ReactElement {
borderRadius="1"
p="1"
mb="1"
backgroundColor={props.highlighted ? 'lightBlue' : 'white'}
backgroundColor={props.highlighted ? 'washedBlue' : 'white'}
>
<MentionText
transcluded={0}

View File

@ -22,7 +22,6 @@ interface CommentsProps {
association: Association;
name: string;
ship: string;
editCommentId: string;
baseUrl: string;
api: GlobalApi;
group: Group;