From fd4edbd6a854275c10c5b21173f0875921d547d1 Mon Sep 17 00:00:00 2001 From: "Thomas F. K. Jorna" Date: Thu, 7 Oct 2021 01:42:14 +0200 Subject: feat(preview): hover links + ui upgrade --- components/Sidebar/Backlinks.tsx | 55 +++++++++++ components/Sidebar/Link.tsx | 77 +++++++++++++++- components/Sidebar/index.tsx | 195 +++++++++++++++++++++++++++------------ components/contextmenu.tsx | 19 ++-- 4 files changed, 276 insertions(+), 70 deletions(-) create mode 100644 components/Sidebar/Backlinks.tsx (limited to 'components') 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 ( + + {'Backlinks (' + links.length + ')'} + } + align="stretch" + color="gray.800" + > + {previewNode?.id && + links.map((link: LinkObject, i: number) => { + const [source, target] = normalizeLinkEnds(link) + if (source === previewNode?.id) { + return + } + return ( + + + + ) + })} + + + ) +} 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 {id} + return ( + <> + + + + + + + + {children} + + + + + {uri && {processor.processSync(previewText).result}} + + + + + + ) } 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() - 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 ( - + - } - colorScheme="white" - aria-label="Close file-viewer" - height={100} - variant="ghost" - marginRight={-2} - bg="alt.100" - onClick={onClose} - marginTop={20} - /> - + - {previewRoamNode?.title} + + } + aria-label="Previous node" + /> + + {previewRoamNode?.title} + + + + } + aria-label="Close file-viewer" + variant="link" + onClick={onClose} + /> { autoHide renderThumbVertical={({ style, ...props }) => ( )} > - + { 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, + }, }} > - + {previewNode?.id && ( + + + , + , + , + , + ][justification] + } + onClick={() => setJustification((curr) => (curr + 1) % 4)} + /> + } + onClick={() => { + console.log(indent) + setIndent((curr: number) => (indent ? 0 : 1)) + }} + /> + } + onClick={() => { + setFont((curr: string) => + curr === 'sans serif' ? 'serif' : 'sans serif', + ) + }} + /> + + + + + + + )} 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) => { }>Open in Zotero )} {scope.nodeIds.length === 0 && ( - } onClick={() => handleLocal(node!, 'replace')}> + } onClick={() => handleLocal(node!, 'replace')}> Open local graph )} @@ -149,6 +150,15 @@ export const ContextMenu = (props: ContextMenuProps) => { */} + + } + onClick={() => { + setPreviewNode(node) + }} + > + Preview + {node?.level === 0 && ( { Permenantly delete note )} - { - setPreviewNode(node) - }} - > - Preview - -- cgit v1.2.3