diff options
author | Thomas F. K. Jorna <[email protected]> | 2021-08-05 21:30:12 +0200 |
---|---|---|
committer | Thomas F. K. Jorna <[email protected]> | 2021-08-05 21:30:12 +0200 |
commit | 54507855a316df0a428119093a16c5e5180fc56d (patch) | |
tree | 6f0b5373f72a07a54f7033b08d435ee836f4e56f | |
parent | 6685a50208a283c90ea1567f731b4d85adc90694 (diff) |
fix: update notes smoothly
-rw-r--r-- | components/contextmenu.tsx | 313 | ||||
-rw-r--r-- | components/tweaks.tsx | 3 | ||||
-rw-r--r-- | org-roam-ui.el | 7 | ||||
-rw-r--r-- | pages/index.tsx | 105 |
4 files changed, 243 insertions, 185 deletions
diff --git a/components/contextmenu.tsx b/components/contextmenu.tsx index 442b956..228a780 100644 --- a/components/contextmenu.tsx +++ b/components/contextmenu.tsx @@ -1,106 +1,120 @@ import React, { useRef } from 'react' import { - Box, - Menu, - MenuItem, - MenuList, - MenuGroup, - MenuItemOption, - MenuOptionGroup, - Heading, - MenuDivider, - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - useDisclosure, - Button, - PopoverTrigger, - PopoverContent, - Popover, - Flex, - PopoverBody, - PopoverCloseButton, - PopoverArrow, - PopoverHeader, - PopoverFooter, - Portal, - Text, - VStack, + Box, + Menu, + MenuItem, + MenuList, + MenuGroup, + MenuItemOption, + MenuOptionGroup, + Heading, + MenuDivider, + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalFooter, + ModalBody, + ModalCloseButton, + useDisclosure, + Button, + PopoverTrigger, + PopoverContent, + Popover, + Flex, + PopoverBody, + PopoverCloseButton, + PopoverArrow, + PopoverHeader, + PopoverFooter, + Portal, + Text, + VStack, } from '@chakra-ui/react' import { - DeleteIcon, - EditIcon, - CopyIcon, - AddIcon, - ViewIcon, - ExternalLinkIcon, - ChevronRightIcon, - PlusSquareIcon, + DeleteIcon, + EditIcon, + CopyIcon, + AddIcon, + ViewIcon, + ExternalLinkIcon, + ChevronRightIcon, + PlusSquareIcon, } from '@chakra-ui/icons' import { OrgRoamGraphReponse, OrgRoamLink, OrgRoamNode } from '../api' export default interface ContextMenuProps { - background: Boolean - node?: OrgRoamNode - nodeType?: string - coordinates: number[] - handleLocal: (node: OrgRoamNode, add: string) => void - openNodeInEmacs: (node: OrgRoamNode) => void - menuClose: () => void - scope: { nodeIds: string[] } - deleteNodeInEmacs: (node: OrgRoamNode) => void + background: Boolean + node?: OrgRoamNode + nodeType?: string + coordinates: number[] + handleLocal: (node: OrgRoamNode, add: string) => void + openNodeInEmacs: (node: OrgRoamNode) => void + menuClose: () => void + scope: { nodeIds: string[] } + deleteNodeInEmacs: (node: OrgRoamNode) => void } export const ContextMenu = (props: ContextMenuProps) => { - const { background, node, nodeType, coordinates, handleLocal, menuClose, scope, openNodeInEmacs, deleteNodeInEmacs } = props - const { isOpen, onOpen, onClose } = useDisclosure() - const copyRef = useRef<any>() - return ( - <> - <Box - position="absolute" - zIndex="overlay" - left={coordinates[0] + 10} - top={coordinates[1] - 10} - padding={5} - > - <Menu closeOnBlur={false} defaultIsOpen onClose={() => menuClose()}> - <MenuList zIndex="overlay" bgColor="alt.100" borderColor="gray.500" maxWidth="xs"> - {node && ( - <> - <Heading size="sm" isTruncated px={3} py={1}> - {node.title} - </Heading> - <MenuDivider borderColor="gray.500" /> - </> - )} - {scope.nodeIds.length !== 0 && - <> - <MenuItem onClick={() => handleLocal(node!, "add")} icon={<PlusSquareIcon />}> - Expand local graph at node - </MenuItem> - <MenuItem onClick={() => handleLocal(node!, "replace")} icon={<ViewIcon />}> - Open local graph for this node - </MenuItem> - </> - } - {!node?.properties.FILELESS ? ( - <MenuItem icon={<EditIcon />} onClick={() => openNodeInEmacs(node as OrgRoamNode)}>Open in Emacs</MenuItem> - ) : ( - <MenuItem icon={<AddIcon />}>Create node</MenuItem> - )} - {node?.properties.ROAM_REFS && ( - <MenuItem icon={<ExternalLinkIcon />}>Open in Zotero</MenuItem> - )} - {scope.nodeIds.length === 0 && - <MenuItem icon={<ViewIcon />} onClick={() => handleLocal(node!, "replace")}>Open local graph</MenuItem> - } - {/* Doesn't work at the moment + const { + background, + node, + nodeType, + coordinates, + handleLocal, + menuClose, + scope, + openNodeInEmacs, + deleteNodeInEmacs, + } = props + const { isOpen, onOpen, onClose } = useDisclosure() + const copyRef = useRef<any>() + return ( + <> + <Box + position="absolute" + zIndex="overlay" + left={coordinates[0] + 10} + top={coordinates[1] - 10} + padding={5} + > + <Menu closeOnBlur={false} defaultIsOpen onClose={() => menuClose()}> + <MenuList zIndex="overlay" bgColor="alt.100" borderColor="gray.500" maxWidth="xs"> + {node && ( + <> + <Heading size="sm" isTruncated px={3} py={1}> + {node.title} + </Heading> + <MenuDivider borderColor="gray.500" /> + </> + )} + {scope.nodeIds.length !== 0 && ( + <> + <MenuItem onClick={() => handleLocal(node!, 'add')} icon={<PlusSquareIcon />}> + Expand local graph at node + </MenuItem> + <MenuItem onClick={() => handleLocal(node!, 'replace')} icon={<ViewIcon />}> + Open local graph for this node + </MenuItem> + </> + )} + {!node?.properties.FILELESS ? ( + <MenuItem icon={<EditIcon />} onClick={() => openNodeInEmacs(node as OrgRoamNode)}> + Open in Emacs + </MenuItem> + ) : ( + <MenuItem icon={<AddIcon />}>Create node</MenuItem> + )} + {node?.properties.ROAM_REFS && ( + <MenuItem icon={<ExternalLinkIcon />}>Open in Zotero</MenuItem> + )} + {scope.nodeIds.length === 0 && ( + <MenuItem icon={<ViewIcon />} onClick={() => handleLocal(node!, 'replace')}> + Open local graph + </MenuItem> + )} + {/* Doesn't work at the moment <MenuItem closeOnSelect={false} closeOnBlur={false}> <Box _hover={{ bg: 'gray.200' }} width="100%"> <Popover @@ -129,63 +143,66 @@ export const ContextMenu = (props: ContextMenuProps) => { </Popover> </Box> </MenuItem> */} - {node?.level === 0 && - <MenuItem - closeOnSelect={false} - icon={<DeleteIcon color="red.500" />} - color="red.500" - onClick={onOpen} - > - Permenantly delete note - </MenuItem> - } - </MenuList> - </Menu> - </Box> - <Modal isCentered isOpen={isOpen} onClose={onClose}> - <ModalOverlay /> - <ModalContent zIndex="popover" > - <ModalHeader>Delete node?</ModalHeader> - <ModalCloseButton /> - <ModalBody> - <VStack - spacing={4} - display="flex" - alignItems="flex-start"> - <Text> - This will permanently delete your note: - </Text> - <Text fontWeight="bold">{node?.title} - </Text> - {node?.level !== 0 && - <Text>This will only delete the from this heading until but not including the next node. - Your parent file and all other nodes will not be deleted.</Text>} - <Text> - Are you sure you want to do continue? - </Text> - </VStack> - </ModalBody> - <ModalFooter> - <Button mr={3} onClick={() => { - console.log('closing') - onClose() - }}> - Cancel - </Button> - <Button variant="link" colorScheme="red" ml={3} - onClick={() => { - console.log('aaaaa') - deleteNodeInEmacs(node!) - onClose() - }} - > - Delete node - </Button> - </ModalFooter> - </ModalContent> - </Modal> - </> - ) + {node?.level === 0 && ( + <MenuItem + closeOnSelect={false} + icon={<DeleteIcon color="red.500" />} + color="red.500" + onClick={onOpen} + > + Permenantly delete note + </MenuItem> + )} + </MenuList> + </Menu> + </Box> + <Modal isCentered isOpen={isOpen} onClose={onClose}> + <ModalOverlay /> + <ModalContent zIndex="popover"> + <ModalHeader>Delete node?</ModalHeader> + <ModalCloseButton /> + <ModalBody> + <VStack spacing={4} display="flex" alignItems="flex-start"> + <Text>This will permanently delete your note:</Text> + <Text fontWeight="bold">{node?.title}</Text> + {node?.level !== 0 && ( + <Text> + This will only delete the from this heading until but not including the next node. + Your parent file and all other nodes will not be deleted. + </Text> + )} + <Text>Are you sure you want to do continue?</Text> + </VStack> + </ModalBody> + <ModalFooter> + <Button + mr={3} + onClick={() => { + console.log('closing') + onClose() + menuClose() + }} + > + Cancel + </Button> + <Button + variant="link" + colorScheme="red" + ml={3} + onClick={() => { + console.log('aaaaa') + deleteNodeInEmacs(node!) + onClose() + menuClose() + }} + > + Delete node + </Button> + </ModalFooter> + </ModalContent> + </Modal> + </> + ) } /* <Box> diff --git a/components/tweaks.tsx b/components/tweaks.tsx index e23476e..9ff994e 100644 --- a/components/tweaks.tsx +++ b/components/tweaks.tsx @@ -1130,6 +1130,9 @@ export const Tweaks = (props: TweakProps) => { <Portal> {' '} <MenuList bgColor="gray.200" zIndex="popover"> + <MenuItem onClick={() => setBehavior({ ...behavior, follow: 'color' })}> + Just coloring the currently opened node + </MenuItem> <MenuItem onClick={() => setBehavior({ ...behavior, follow: 'local' })}> Opening the local graph </MenuItem> diff --git a/org-roam-ui.el b/org-roam-ui.el index b3c3ace..fe0eb1b 100644 --- a/org-roam-ui.el +++ b/org-roam-ui.el @@ -151,11 +151,10 @@ This serves the web-build and API over HTTP." :id (alist-get 'id data))))) ((string= command "delete") (progn - (delete-file (alist-get 'file data) - (message "Deleted %s" (alist-get 'file data)))) + (message "Deleted %s" (alist-get 'file data)) + (delete-file (alist-get 'file data)) (org-roam-db-sync) - (org-roam-ui--update-graphdata "node" "deleted" (alist-get 'id data)) - ) + (org-roam-ui--send-graphdata))) (t (message "Something went wrong when receiving a message from Org-Roam-UI"))))) :on-close (lambda (_websocket) (remove-hook 'after-save-hook #'org-roam-ui--on-save) diff --git a/pages/index.tsx b/pages/index.tsx index fb12906..c521741 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -161,7 +161,7 @@ export function GraphPage() { const newNodes = [ ...currentGraphData.nodes.map((node: NodeObject) => { - const newNode = nodeByIdRef.current[node.id!] ?? false + const newNode = nodeByIdRef.current[node?.id!] ?? false if (!newNode) { return } @@ -169,9 +169,21 @@ export function GraphPage() { }), ...Object.keys(nodeByIdRef.current) .filter((id) => !oldNodeById[id]) - .map((id) => nodeByIdRef.current[id] as NodeObject), + .map((id) => { + console.log(id) + return nodeByIdRef.current[id] as NodeObject + }), ] + const nodeIndex = newNodes.reduce((acc, node, index) => { + const id = node?.id as string + return { + ...acc, + [id]: index, + } + }, {}) + console.log(newNodes) + console.log(nodeIndex) /* const currentGraphIndexByLink = currentGraphData.links.reduce<{[key: string]: number}>((acc, link, index) => { * const [source, target] = normalizeLinkEnds(link) * const sourceTarget=source+target @@ -180,33 +192,56 @@ export function GraphPage() { * [sourceTarget]: index * } },{}) */ + const newLinks = [ + ...currentGraphData!.links.filter((link) => { + const [source, target] = normalizeLinkEnds(link) + if (!nodeByIdRef.current[source] || !nodeByIdRef.current[target]) { + return false + } + if ( + !linksByNodeIdRef.current[source]!.some( + (link) => link.target === target || link.source === target, + ) && + !linksByNodeIdRef.current[target]!.some( + (link) => link.target === source || link.source === source, + ) + ) { + return false + } + return true + }), + ...Object.keys(linksByNodeIdRef.current).flatMap((id) => { + if (!oldLinksByNodeId[id]!) { + return linksByNodeIdRef.current![id!]! + } + return ( + linksByNodeIdRef.current![id]!.filter((link) => { + const [source, target] = normalizeLinkEnds(link) + return !oldLinksByNodeId[id]!.some( + (oldLink) => oldLink.source === source && oldLink.target === target, + )! + }) ?? [] + ) + }), + ] - /* const newLinks = graphData!.links.filter(link => { - * const [source, target] = normalizeLinkEnds(link) - * if (!nodeByIdRef.current[source] || !nodeByIdRef.current[target]) { - * return false - * } - * if (!linksByNodeIdRef.current[source]!.some(link => link.target === target || link.source === target) - * && !linksByNodeIdRef.current[target]!.some(link => link.target === source || link.source === source)) { - * return false - * } - * return true - * }) - * console.log(newLinks) - * console.log(currentGraphData.links) */ - /* ...Object.keys(linksByNodeIdRef.current).flatMap((id) => { -if (!oldLinksByNodeId[id]!) { -return linksByNodeIdRef.current![id!]! -} -return linksByNodeIdRef.current![id]!.filter(link => { -const [source, target] = normalizeLinkEnds(link) -return !oldLinksByNodeId[id]!.some(oldLink => oldLink.source === source && oldLink.target === target)! -}) ?? [] -})] */ + const newerLinks = links.map((link) => { + const [source, target] = normalizeLinkEnds(link) + return { + ...link, + source: newNodes[nodeIndex[source]], + target: newNodes[nodeIndex[target]], + } + }) const fg = graphRef.current - fg.cooldownTicks = 0 - setGraphData({ nodes: newNodes as NodeObject[], links: links }) + setGraphData({ nodes: newNodes as NodeObject[], links: newerLinks }) } + useEffect(() => { + if (!graphData) { + return + } + currentGraphDataRef.current = graphData + }, [graphData]) const { setEmacsTheme } = useContext(ThemeContext) @@ -225,6 +260,9 @@ return !oldLinksByNodeId[id]!.some(oldLink => oldLink.source === source && oldLi speed: number = 2000, padding: number = 200, ) => { + if (command === 'color') { + return + } const fg = graphRef.current const sr = scopeRef.current const bh = behaviorRef.current @@ -442,11 +480,9 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { } const deleteNodeInEmacs = (node: OrgRoamNode) => { - console.log('deletin') if (node.level !== 0) { return } - console.log('deletin') sendMessageToEmacs('delete', { id: node.id, file: node.file }) } @@ -509,6 +545,11 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { hiddenNodeIdsRef.current = {} const filteredNodes = graphData?.nodes ?.filter((nodeArg) => { + //sometimes there will be some undefined nodes in the mix + // should probably fix the actual issue, but this is a fix + if (!nodeArg) { + return + } const node = nodeArg as OrgRoamNode if ( filter.tagsBlacklist.length && @@ -530,9 +571,8 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { } return true }) - .filter((nodeArg) => { - const node = nodeArg as OrgRoamNode - const links = linksByNodeId[node.id as string] ?? [] + .filter((node) => { + const links = linksByNodeId[node?.id as string] ?? [] const unhiddenLinks = links.filter( (link) => !hiddenNodeIdsRef.current[link.source] && !hiddenNodeIdsRef.current[link.target], @@ -822,7 +862,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { setContextPos([event.pageX, event.pageY]) setRightClickedNode(node) onOpen() - console.log(event) } const graphCommonProps: ComponentPropsWithoutRef<typeof TForceGraph2D> = { @@ -1059,7 +1098,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { function isLinkRelatedToNode(link: LinkObject, node: NodeObject | null) { return ( - (link.source as NodeObject).id! === node?.id! || (link.target as NodeObject).id! === node?.id! + (link.source as NodeObject)?.id! === node?.id! || (link.target as NodeObject)?.id! === node?.id! ) } |