summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/contextmenu.tsx313
-rw-r--r--components/tweaks.tsx3
-rw-r--r--org-roam-ui.el7
-rw-r--r--pages/index.tsx105
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!
)
}