summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/Sidebar/Backlinks.tsx55
-rw-r--r--components/Sidebar/Link.tsx77
-rw-r--r--components/Sidebar/index.tsx195
-rw-r--r--components/contextmenu.tsx19
4 files changed, 276 insertions, 70 deletions
diff --git a/components/Sidebar/Backlinks.tsx b/components/Sidebar/Backlinks.tsx
new file mode 100644
index 0000000..f899d3e
--- /dev/null
+++ b/components/Sidebar/Backlinks.tsx
@@ -0,0 +1,55 @@
+import { LinksByNodeId, NodeById } from '../../pages/index'
+
+import { GraphData, NodeObject, LinkObject } from 'force-graph'
+
+import { normalizeLinkEnds } from '../../pages/index'
+import { VStack, Box, Button, Heading, StackDivider } from '@chakra-ui/react'
+import React from 'react'
+import { ProcessedOrg } from '../../util/processOrg'
+
+export interface BacklinksProps {
+ previewNode: any
+ setPreviewNode: any
+ nodeById: NodeById
+ linksByNodeId: LinksByNodeId
+ getText: any
+}
+
+import { PreviewLink } from './Link'
+
+export const Backlinks = (props: BacklinksProps) => {
+ const { previewNode, setPreviewNode, nodeById, linksByNodeId, getText } = props
+ const links = linksByNodeId[previewNode?.id] ?? []
+ return (
+ <Box>
+ <Heading pt={4}>{'Backlinks (' + links.length + ')'}</Heading>
+ <VStack
+ pt={2}
+ spacing={3}
+ alignItems="start"
+ divider={<StackDivider borderColor="gray.500" />}
+ align="stretch"
+ color="gray.800"
+ >
+ {previewNode?.id &&
+ links.map((link: LinkObject, i: number) => {
+ const [source, target] = normalizeLinkEnds(link)
+ if (source === previewNode?.id) {
+ return
+ }
+ return (
+ <Box overflow="hidden" p={3} bg="gray.300" width="100%" key={source}>
+ <PreviewLink
+ href={'id:' + source}
+ children={nodeById[source]?.title}
+ nodeById={nodeById}
+ setPreviewNode={setPreviewNode}
+ getText={getText}
+ />
+ </Box>
+ )
+ })}
+ </VStack>
+ </Box>
+ )
+}
diff --git a/components/Sidebar/Link.tsx b/components/Sidebar/Link.tsx
index 789873a..ff812ef 100644
--- a/components/Sidebar/Link.tsx
+++ b/components/Sidebar/Link.tsx
@@ -1,11 +1,78 @@
-import { Text } from '@chakra-ui/react'
+import {
+ Box,
+ Button,
+ Popover,
+ PopoverArrow,
+ PopoverBody,
+ PopoverCloseButton,
+ PopoverContent,
+ PopoverHeader,
+ PopoverTrigger,
+ Portal,
+ Text,
+} from '@chakra-ui/react'
+import React, { useState } from 'react'
+import UniOrg from '../../util/uniorg'
+
+import unified from 'unified'
+//import createStream from 'unified-stream'
+import uniorgParse from 'uniorg-parse'
+import uniorg2rehype from 'uniorg-rehype'
+//import highlight from 'rehype-highlight'
+import katex from 'rehype-katex'
+import 'katex/dist/katex.css'
+import rehype2react from 'rehype-react'
export interface LinkProps {
- id: string
+ href: string
+ children: any
+ testProp: string
+ getText: any
+ previewNode?: any
+ setPreviewNode: any
}
-export const Link = (props: LinkProps) => {
- const { id } = props
+export const PreviewLink = (props: any) => {
+ const { href, children, nodeById, getText, previewNode, setPreviewNode } = props
+ const [previewText, setPreviewText] = useState('')
+ const [whatever, type, uri] = [...href.matchAll(/(.*?)\:(.*)/g)][0]
+
+ const processor = unified().use(uniorgParse).use(uniorg2rehype).use(katex).use(rehype2react, {
+ createElement: React.createElement,
+ // eslint-disable-next-line react/display-name
+ })
+
+ type === 'id' && getText(uri, setPreviewText)
- return <Text>{id}</Text>
+ return (
+ <>
+ <Popover trigger="hover" isLazy position="relative" zIndex="tooltip">
+ <PopoverTrigger>
+ <Button size="sm" onClick={() => setPreviewNode(nodeById[uri])} variant="link">
+ {children}
+ </Button>
+ </PopoverTrigger>
+ <Portal zIndex={100000} position="relative">
+ <PopoverContent boxShadow="xl" position="relative" zIndex="tooltip">
+ <PopoverHeader pl={5} fontSize="sm" zIndex="tooltip" fontWeight="semibold">
+ {children}
+ </PopoverHeader>
+ <PopoverArrow zIndex={10000} />
+ <PopoverCloseButton zIndex={10000} />
+ <PopoverBody
+ pb={5}
+ fontSize="xs"
+ px={5}
+ position="relative"
+ zIndex="tooltip"
+ maxHeight={300}
+ overflow="scroll"
+ >
+ {uri && <Box>{processor.processSync(previewText).result}</Box>}
+ </PopoverBody>
+ </PopoverContent>
+ </Portal>
+ </Popover>
+ </>
+ )
}
diff --git a/components/Sidebar/index.tsx b/components/Sidebar/index.tsx
index 4f314da..e56a25d 100644
--- a/components/Sidebar/index.tsx
+++ b/components/Sidebar/index.tsx
@@ -1,6 +1,7 @@
import React, { useContext, useEffect, useState } from 'react'
import { UniOrg } from '../../util/uniorg'
+import { Backlinks } from './Backlinks'
import { getOrgText } from '../../util/webSocketFunctions'
import {
@@ -22,90 +23,98 @@ import {
IconButton,
} from '@chakra-ui/react'
import { Scrollbars } from 'react-custom-scrollbars-2'
-import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons'
+import { ChevronLeftIcon, ChevronRightIcon, HamburgerIcon } from '@chakra-ui/icons'
+import {
+ BiFont,
+ BiAlignJustify,
+ BiAlignLeft,
+ BiAlignMiddle,
+ BiAlignRight,
+ BiRightIndent,
+} from 'react-icons/bi'
import { GraphData, NodeObject, LinkObject } from 'force-graph'
import { OrgRoamNode } from '../../api'
import { ThemeContext } from '../../util/themecontext'
+import { LinksByNodeId, NodeById } from '../../pages/index'
export interface SidebarProps {
isOpen: boolean
onClose: any
- //nodeById: any
+ onOpen: any
+ nodeById: NodeById
previewNode: NodeObject
+ setPreviewNode: any
+ linksByNodeId: LinksByNodeId
}
const Sidebar = (props: SidebarProps) => {
- const { isOpen, onClose, previewNode } = props
+ const { isOpen, onOpen, onClose, previewNode, setPreviewNode, nodeById, linksByNodeId } = props
const { highlightColor } = useContext(ThemeContext)
const [previewRoamNode, setPreviewRoamNode] = useState<OrgRoamNode>()
- const [previewText, setPreviewText] = useState('')
- const getText = (id: string) => {
+ const getText = (id: string, setText: any) => {
fetch(`http://localhost:35901/note/${id}`)
.then((res) => {
return res.text()
})
- .then((res) => {
- console.log(res)
- setPreviewText(res)
- })
+ .then((res) => setText(res))
.catch((e) => {
- setPreviewText(
+ return (
'Could not fetch the text for some reason, sorry!\n\n This can happen because you have an id with forward slashes (/) in it.',
+ console.log(e)
)
})
}
useEffect(() => {
- if (!previewNode) {
+ if (!previewNode.id) {
+ onClose()
return
}
-
+ onOpen()
setPreviewRoamNode(previewNode as OrgRoamNode)
- previewNode?.id && getText(previewNode?.id as string)
- }, [previewNode])
+ }, [previewNode.id])
+ const [justification, setJustification] = useState(0)
+ const justificationList = ['justify', 'start', 'end', 'center']
+ const [font, setFont] = useState('sans serif')
+ const [indent, setIndent] = useState(0)
//maybe want to close it when clicking outside, but not sure
//const outsideClickRef = useRef();
return (
- <Slide direction="right" in={isOpen} style={{ zIndex: 200, width: 500 }} unmountOnExit>
+ <Slide direction="right" in={isOpen} style={{ maxWidth: '50%' }} unmountOnExit>
<Flex flexDirection="row" height="100%">
- <IconButton
- icon={<ChevronRightIcon height={30} />}
- colorScheme="white"
- aria-label="Close file-viewer"
- height={100}
- variant="ghost"
- marginRight={-2}
- bg="alt.100"
- onClick={onClose}
- marginTop={20}
- />
- <Box
- color="gray.800"
- bg="alt.100"
- boxShadow="xl"
- w={500}
- height="98%"
- position="relative"
- zIndex="overlay"
- marginTop={10}
- paddingBottom={15}
- borderRadius="xl"
- right={-2}
- >
+ <Box pl={2} color="gray.800" bg="alt.100" w="100%" paddingBottom={15}>
<Flex
justifyContent="space-between"
- padding={4}
- paddingTop={10}
- paddingLeft={10}
- width="80%"
+ paddingTop={4}
+ pl={0}
+ pb={5}
+ pr={2}
alignItems="center"
color="black"
>
- <Heading size="md">{previewRoamNode?.title}</Heading>
+ <Flex>
+ <IconButton
+ variant="link"
+ size="md"
+ icon={<ChevronLeftIcon />}
+ aria-label="Previous node"
+ />
+ <Heading size="md" fontWeight={400}>
+ {previewRoamNode?.title}
+ </Heading>
+ </Flex>
+
+ <IconButton
+ // eslint-disable-next-line react/jsx-no-undef
+ icon={<HamburgerIcon />}
+ aria-label="Close file-viewer"
+ variant="link"
+ onClick={onClose}
+ />
</Flex>
<Scrollbars
//autoHeight
@@ -113,40 +122,43 @@ const Sidebar = (props: SidebarProps) => {
autoHide
renderThumbVertical={({ style, ...props }) => (
<Box
- {...props}
style={{
...style,
borderRadius: 10,
+ backgroundColor: highlightColor,
}}
- bg={highlightColor}
+ color="black"
+ {...props}
/>
)}
>
- <VStack alignItems="left" bg="alt.100" paddingLeft={10} paddingRight={10}>
+ <VStack height="100%" alignItems="left" bg="alt.100" paddingLeft={10}>
<Box
+ pr={8}
+ overflow="scroll"
+ height="85%"
className="org"
sx={{
- h1: { display: 'none' },
+ '.katex': { overflowX: 'scroll' },
+ h1: { fontSize: '20', fontWeight: 'bold', marginBottom: 3 },
h2: {
- fontSize: '20',
- fontWeight: 'bold !important',
- marginBottom: '1em',
+ fontSize: '18',
+ marginBottom: 2,
color: 'black',
},
h3: {
- fontSize: '18',
+ fontSize: '16',
fontWeight: '600 !important',
marginBottom: '.5em',
},
h4: {
- fontSize: '16',
+ fontSize: '14',
fontWeight: '500 !important',
marginBottom: '.25em',
fontStyle: 'italic',
},
a: {
color: highlightColor,
- pointerEvents: 'none',
},
ol: {
paddingLeft: '5',
@@ -157,8 +169,11 @@ const Sidebar = (props: SidebarProps) => {
p: {
paddingBottom: '.5em',
},
- '.katex-html': { visibility: 'hidden', width: '0px', position: 'absolute' },
- '#content': { textAlign: 'justify' },
+ div: {
+ fontSize: 'small',
+ hyphens: 'auto !important',
+ textAlign: justificationList[justification],
+ },
'.title': {
textAlign: 'center',
marginBottom: '.2em',
@@ -261,9 +276,75 @@ const Sidebar = (props: SidebarProps) => {
'.footdef': { marginBottom: '1em' },
'.figure': { padding: '1em' },
'.figure p': { textAlign: 'center' },
+ // org-like indents
+ 'h1, h1 ~ *,h2 ~ h1,h2 ~ h1 ~ *,h3 ~ h1,h3 ~ h1 ~ *': {
+ marginLeft: 0 * indent,
+ },
+ 'h2 ~ *, h1 ~ h2,h1 ~ h2 ~ *:not(h1):not(h3)': {
+ marginLeft: 2 * indent,
+ },
+ 'h3 ~ *,h1 ~ h3,h1 ~ h3 ~ *:not(h1):not(h2)': {
+ marginLeft: 4 * indent,
+ },
}}
>
- <UniOrg orgText={previewText} />
+ {previewNode?.id && (
+ <Box>
+ <Flex pt={1} alignItems="center" justifyContent="flex-end">
+ <IconButton
+ variant="ghost"
+ aria-label="Justify content"
+ icon={
+ [
+ <BiAlignJustify key="justify" />,
+ <BiAlignLeft key="left" />,
+ <BiAlignRight key="right" />,
+ <BiAlignMiddle key="center" />,
+ ][justification]
+ }
+ onClick={() => setJustification((curr) => (curr + 1) % 4)}
+ />
+ <IconButton
+ variant="ghost"
+ aria-label="Indent Text"
+ icon={<BiRightIndent />}
+ onClick={() => {
+ console.log(indent)
+ setIndent((curr: number) => (indent ? 0 : 1))
+ }}
+ />
+ <IconButton
+ variant="ghost"
+ aria-label="Change font"
+ icon={<BiFont />}
+ onClick={() => {
+ setFont((curr: string) =>
+ curr === 'sans serif' ? 'serif' : 'sans serif',
+ )
+ }}
+ />
+ </Flex>
+ <Flex height="100%" flexDirection="column" justifyContent="space-between">
+ <UniOrg
+ {...{
+ getText,
+ setPreviewNode,
+ previewNode,
+ nodeById,
+ }}
+ />
+ <Backlinks
+ {...{
+ setPreviewNode,
+ previewNode,
+ nodeById,
+ linksByNodeId,
+ getText,
+ }}
+ />
+ </Flex>
+ </Box>
+ )}
</Box>
</VStack>
</Scrollbars>
diff --git a/components/contextmenu.tsx b/components/contextmenu.tsx
index 09d9cff..73758a5 100644
--- a/components/contextmenu.tsx
+++ b/components/contextmenu.tsx
@@ -44,6 +44,7 @@ import {
import { OrgRoamGraphReponse, OrgRoamLink, OrgRoamNode } from '../api'
import { deleteNodeInEmacs, openNodeInEmacs, createNodeInEmacs } from '../util/webSocketFunctions'
+import { BiNetworkChart } from 'react-icons/bi'
export default interface ContextMenuProps {
background: Boolean
@@ -116,7 +117,7 @@ export const ContextMenu = (props: ContextMenuProps) => {
<MenuItem icon={<ExternalLinkIcon />}>Open in Zotero</MenuItem>
)}
{scope.nodeIds.length === 0 && (
- <MenuItem icon={<ViewIcon />} onClick={() => handleLocal(node!, 'replace')}>
+ <MenuItem icon={<BiNetworkChart />} onClick={() => handleLocal(node!, 'replace')}>
Open local graph
</MenuItem>
)}
@@ -149,6 +150,15 @@ export const ContextMenu = (props: ContextMenuProps) => {
</Popover>
</Box>
</MenuItem> */}
+
+ <MenuItem
+ icon={<ViewIcon />}
+ onClick={() => {
+ setPreviewNode(node)
+ }}
+ >
+ Preview
+ </MenuItem>
{node?.level === 0 && (
<MenuItem
closeOnSelect={false}
@@ -159,13 +169,6 @@ export const ContextMenu = (props: ContextMenuProps) => {
Permenantly delete note
</MenuItem>
)}
- <MenuItem
- onClick={() => {
- setPreviewNode(node)
- }}
- >
- Preview
- </MenuItem>
</MenuList>
</Menu>
</Box>