diff --git a/pkg/interface/src/views/apps/graph/app.js b/pkg/interface/src/views/apps/graph/app.js index 6daf7c449c..de780e51b7 100644 --- a/pkg/interface/src/views/apps/graph/app.js +++ b/pkg/interface/src/views/apps/graph/app.js @@ -4,16 +4,38 @@ import { Center, Text } from "@tlon/indigo-react"; import { deSig } from '~/logic/lib/util'; import useGraphState from '~/logic/state/graph'; import useMetadataState from '~/logic/state/metadata'; +import useGroupState from '~/logic/state/group'; +import { GraphIndexRoute } from './graphIndex'; const GraphApp = (props) => { const associations= useMetadataState(state => state.associations); const graphKeys = useGraphState(state => state.graphKeys); + const groups = useGroupState(state => state.groups); const history = useHistory(); const { api } = props; return ( + { + const resource = + `${deSig(props.match.params.ship)}/${props.match.params.name}`; + const { ship, name } = props.match.params; + const path = `/ship/~${deSig(ship)}/${name}`; + const association = associations.graph[path]; + const url = `/~graph/graph/ship/${ship}/${name}`; + const group = groups[association.group]; + if(!(group && association)) { + return null; + } + + return ( + + ); + + }} + /> { const resource = @@ -52,4 +74,4 @@ const GraphApp = (props) => { ); } -export default GraphApp; \ No newline at end of file +export default GraphApp; diff --git a/pkg/interface/src/views/apps/graph/graphIndex.tsx b/pkg/interface/src/views/apps/graph/graphIndex.tsx new file mode 100644 index 0000000000..e5e4c363f4 --- /dev/null +++ b/pkg/interface/src/views/apps/graph/graphIndex.tsx @@ -0,0 +1,122 @@ +import React from "react"; +import _ from "lodash"; +import { Switch, Route, Redirect } from "react-router-dom"; +import { Association, Group } from "@urbit/api"; + +export function getGraphPermalink( + assoc: Association, + group: Group, + index: string +) { + const mod = assoc.metadata.module; + const groupPath = group.hidden + ? "/~/landscape/home" + : `/~landscape${assoc.group}`; + if (mod === "chat") { + return getChatPermalink( + group.hidden ? "/~landscape/messages" : `/~landscape${assoc.group}`, + assoc, + index + ); + } else if (mod === "publish") { + return getPublishPermalink(groupPath, assoc, index); + } else if (mod === "link") { + return getLinkPermalink(groupPath, assoc, index); + } + return "/~404"; +} + +function getPublishPermalink( + groupPath: string, + assoc: Association, + index: string +) { + const idx = index.split("/").slice(1); + const base = `${groupPath}/resource/publish${assoc.resource}`; + let isComment = false; + const res = _.reduce( + idx, + (acc, val, i) => { + if (i === 0) { + return {...acc, pathname: `${acc.pathname}/note/${val}` }; + } else if (i === 1 && val === '2') { + isComment = true; + return acc; + } else if (i === 2 && isComment) { + return { ...acc, search: `?selected=${val}` }; + } + return acc; + }, + { pathname: base } + ); + return res; +} + +function getLinkPermalink( + groupPath: string, + assoc: Association, + index: string +) { + const idx = index.split("/").slice(1); + const base = `${groupPath}/resource/link${assoc.resource}`; + const res = _.reduce( + idx, + (acc, val, i) => { + console.log(acc); + if (i === 0) { + return {...acc, pathname: `${acc.pathname}/${val}` }; + } else if (i === 1) { + return {...acc, search: `?selected=${val}` }; + } + return acc; + }, + { pathname: base } + ); + return res; +} + +function getChatPermalink( + groupPath: string, + assoc: Association, + index: string +) { + const idx = index.split("/").slice(1); + if (idx.length === 0) { + return `${groupPath}/resource/chat${assoc.resource}`; + } + return `${groupPath}/resource/chat${assoc.resource}?msg=${idx[0]}`; +} + +export function GraphIndexRoute(props: { + association: Association; + group: Group; + index: string; + url: string; +}) { + const { url, index, association, group } = props; + + return ( + + { + const newUrl = `${url}/${match.params.id}`; + const newIndex = `${index}/${match.params.id}`; + return ( + + ); + }} + /> + + + + + ); +} diff --git a/pkg/interface/src/views/apps/links/LinkResource.tsx b/pkg/interface/src/views/apps/links/LinkResource.tsx index b45ffa31ca..526038cd4f 100644 --- a/pkg/interface/src/views/apps/links/LinkResource.tsx +++ b/pkg/interface/src/views/apps/links/LinkResource.tsx @@ -82,7 +82,7 @@ export function LinkResource(props: LinkResourceProps) { }} /> { const index = bigInt(props.match.params.index); const editCommentId = props.match.params.commentId || null; diff --git a/pkg/interface/src/views/components/CommentItem.tsx b/pkg/interface/src/views/components/CommentItem.tsx index 50493f6f6c..a53e7f5139 100644 --- a/pkg/interface/src/views/components/CommentItem.tsx +++ b/pkg/interface/src/views/components/CommentItem.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useEffect, useRef} from 'react'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; @@ -27,10 +27,12 @@ interface CommentItemProps { ship: string; api: GlobalApi; group: Group; + highlighted: boolean; } export function CommentItem(props: CommentItemProps): ReactElement { const { ship, name, api, comment, group } = props; + const ref = useRef(null); const [, post] = getLatestCommentRevision(comment); const disabled = props.pending; @@ -40,13 +42,12 @@ export function CommentItem(props: CommentItemProps): ReactElement { const commentIndexArray = (comment.post?.index || '/').split('/'); const commentIndex = commentIndexArray[commentIndexArray.length - 1]; - const updateUrl = `${props.baseUrl}/${commentIndex}`; const adminLinks: JSX.Element[] = []; const ourRole = roleForShip(group, window.ship); if (window.ship == post?.author && !disabled) { adminLinks.push( - + { + if(props.highlighted) { + ref.current.scrollIntoView(); + } + + }, [props.highlighted]); + return ( - - + + ) { comments, ship, name, - editCommentId, api, history, baseUrl, @@ -40,6 +40,18 @@ export function Comments(props: CommentsProps & PropFunc) { ...rest } = props; + const { query } = useQuery(); + const selectedComment = useMemo(() => { + const id = query.get('selected') + return id ? bigInt(id) : null; + }, [query]); + + const editCommentId = useMemo(() => { + const id = query.get('edit') + return id || ''; + }, [query]); + + const onSubmit = async ( { comment }, actions: FormikHelpers<{ comment: string }> @@ -116,8 +128,8 @@ export function Comments(props: CommentsProps & PropFunc) { return ( - {( !props.editCommentId && canComment ? : null )} - {( props.editCommentId ? ( + {( !editCommentId && canComment ? : null )} + {( editCommentId ? ( ) { /> ) : null )} {children.reverse() - .map(([idx, comment], i) => { + .map(([idx, comment], i) => { + const highlighted = selectedComment?.eq(idx) ?? false; return (