From 546a88ec37073840e98ed689f7139d04985e861c Mon Sep 17 00:00:00 2001 From: "Thomas F. K. Jorna" Date: Mon, 11 Oct 2021 01:13:10 +0200 Subject: feat(preview): ui redo --- components/Sidebar/Backlinks.tsx | 3 + components/Sidebar/Link.tsx | 20 ++++- components/Sidebar/Note.tsx | 4 + components/Sidebar/Toolbar.tsx | 102 +++++++++++++----------- components/Sidebar/index.tsx | 109 +++++++++++++++++++------- components/Tweaks/BehaviorPanel.tsx | 1 + components/Tweaks/SliderWithInfo.tsx | 2 +- components/Tweaks/index.tsx | 27 +++---- components/config.ts | 5 +- components/contextmenu.tsx | 146 ++++++++++++++++++----------------- 10 files changed, 258 insertions(+), 161 deletions(-) (limited to 'components') diff --git a/components/Sidebar/Backlinks.tsx b/components/Sidebar/Backlinks.tsx index 8c1e9bc..68ab551 100644 --- a/components/Sidebar/Backlinks.tsx +++ b/components/Sidebar/Backlinks.tsx @@ -14,6 +14,7 @@ export interface BacklinksProps { linksByNodeId: LinksByNodeId nodeByCite: NodeByCite setSidebarHighlightedNode: OrgRoamNode + openContextMenu: any } import { PreviewLink } from './Link' @@ -27,6 +28,7 @@ export const Backlinks = (props: BacklinksProps) => { nodeById, linksByNodeId, nodeByCite, + openContextMenu, } = props const links = linksByNodeId[previewNode?.id] ?? [] @@ -59,6 +61,7 @@ export const Backlinks = (props: BacklinksProps) => { href={`id:${link as string}`} nodeById={nodeById} setPreviewNode={setPreviewNode} + openContextMenu={openContextMenu} > {nodeById[link as string]?.title} diff --git a/components/Sidebar/Link.tsx b/components/Sidebar/Link.tsx index 16fc2ac..49fe9cf 100644 --- a/components/Sidebar/Link.tsx +++ b/components/Sidebar/Link.tsx @@ -35,6 +35,7 @@ export interface LinkProps { setSidebarHighlightedNode: any nodeByCite: NodeByCite nodeById: NodeById + openContextMenu: any } export interface NormalLinkProps { @@ -44,6 +45,7 @@ export interface NormalLinkProps { href: any children: any setSidebarHighlightedNode: any + openContextMenu: any } import { hexToRGBA, getThemeColor } from '../../pages/index' @@ -51,7 +53,8 @@ import noteStyle from './noteStyle' import { OrgImage } from './OrgImage' export const NormalLink = (props: NormalLinkProps) => { - const { setSidebarHighlightedNode, setPreviewNode, nodeById, href, children } = props + const { setSidebarHighlightedNode, setPreviewNode, nodeById, openContextMenu, href, children } = + props const { highlightColor } = useContext(ThemeContext) const theme = useTheme() @@ -67,12 +70,16 @@ export const NormalLink = (props: NormalLinkProps) => { fontWeight={500} color={highlightColor} textDecoration="underline" + onContextMenu={(e) => { + e.preventDefault() + openContextMenu(nodeById[uri], e) + }} onClick={() => setPreviewNode(nodeById[uri])} // TODO don't hardcode the opacitycolor _hover={{ textDecoration: 'none', cursor: 'pointer', bgColor: coolHighlightColor + '22' }} _focus={{ outlineColor: highlightColor }} > - {nodeById[uri]?.title} + {children} ) } @@ -86,6 +93,7 @@ export const PreviewLink = (props: LinkProps) => { previewNode, setPreviewNode, nodeByCite, + openContextMenu, } = props // TODO figure out how to properly type this // see https://github.com/rehypejs/rehype-react/issues/25 @@ -129,8 +137,9 @@ export const PreviewLink = (props: LinkProps) => { href={href} nodeById={nodeById} setPreviewNode={setPreviewNode} + openContextMenu={openContextMenu} > - {nodeById[id as string]?.title} + {children} ), img: ({ src }) => { @@ -186,6 +195,7 @@ export const PreviewLink = (props: LinkProps) => { href, children, nodeByCite, + openContextMenu, }} /> @@ -213,7 +223,9 @@ export const PreviewLink = (props: LinkProps) => { maxHeight={300} overflow="scroll" > - {orgText} + + {orgText} + diff --git a/components/Sidebar/Note.tsx b/components/Sidebar/Note.tsx index ef2e2b2..e425559 100644 --- a/components/Sidebar/Note.tsx +++ b/components/Sidebar/Note.tsx @@ -16,6 +16,7 @@ export interface NoteProps { justification: number justificationList: string[] linksByNodeId: LinksByNodeId + openContextMenu: any } export const Note = (props: NoteProps) => { @@ -28,6 +29,7 @@ export const Note = (props: NoteProps) => { nodeByCite, setSidebarHighlightedNode, linksByNodeId, + openContextMenu, } = props return ( { nodeById, nodeByCite, setSidebarHighlightedNode, + openContextMenu, }} /> { linksByNodeId, nodeByCite, setSidebarHighlightedNode, + openContextMenu, }} /> diff --git a/components/Sidebar/Toolbar.tsx b/components/Sidebar/Toolbar.tsx index f6f1e39..8741da5 100644 --- a/components/Sidebar/Toolbar.tsx +++ b/components/Sidebar/Toolbar.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Text, Flex, IconButton } from '@chakra-ui/react' +import { Text, Flex, IconButton, ButtonGroup, Tooltip } from '@chakra-ui/react' import { BiAlignJustify, BiAlignLeft, @@ -38,53 +38,65 @@ export const Toolbar = (props: ToolbarProps) => { nextPreviewNode, } = props return ( - + - } - aria-label="Previous node" - disabled={!canUndo} - onClick={() => previousPreviewNode()} - /> - } - aria-label="Next node" - disabled={!canRedo} - onClick={() => nextPreviewNode()} - /> + + + } + aria-label="Previous node" + disabled={!canUndo} + onClick={() => previousPreviewNode()} + /> + + + } + aria-label="Next node" + disabled={!canRedo} + onClick={() => nextPreviewNode()} + /> + + - , - , - , - , - ][justification] - } - onClick={() => setJustification((curr: number) => (curr + 1) % 4)} - /> - } - onClick={() => { - setIndent((curr: number) => (curr ? 0 : 1)) - }} - /> - } - onClick={() => { - setFont((curr: string) => (curr === 'sans serif' ? 'serif' : 'sans serif')) - }} - /> + + , + , + , + , + ][justification] + } + onClick={() => setJustification((curr: number) => (curr + 1) % 4)} + /> + + {/* + } + onClick={() => { + setIndent((curr: number) => (curr ? 0 : 1)) + }} + /> + + + } + onClick={() => { + setFont((curr: string) => (curr === 'sans serif' ? 'serif' : 'sans serif')) + }} + /> + */} ) diff --git a/components/Sidebar/index.tsx b/components/Sidebar/index.tsx index 2e32f4f..cbc0cc9 100644 --- a/components/Sidebar/index.tsx +++ b/components/Sidebar/index.tsx @@ -3,15 +3,19 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import { Toolbar } from './Toolbar' import { Note } from './Note' -import { Button, Slide, VStack, Flex, Heading, Box, IconButton } from '@chakra-ui/react' +import { Button, Slide, VStack, Flex, Heading, Box, IconButton, Tooltip } from '@chakra-ui/react' +import { Collapse } from './Collapse' import { Scrollbars } from 'react-custom-scrollbars-2' -import { ChevronLeftIcon, ChevronRightIcon, HamburgerIcon } from '@chakra-ui/icons' -import { BiFile } from 'react-icons/bi' +import { ChevronLeftIcon, ChevronRightIcon, CloseIcon, HamburgerIcon } from '@chakra-ui/icons' +import { BiDotsVerticalRounded, BiFile, BiNetworkChart } from 'react-icons/bi' +import { BsReverseLayoutSidebarInsetReverse } from 'react-icons/bs' import { GraphData, NodeObject, LinkObject } from 'force-graph' import { OrgRoamNode } from '../../api' import { ThemeContext } from '../../util/themecontext' -import { LinksByNodeId, NodeByCite, NodeById } from '../../pages/index' +import { LinksByNodeId, NodeByCite, NodeById, Scope } from '../../pages/index' +import { Resizable } from 're-resizable' +import { usePersistantState } from '../../util/persistant-state' export interface SidebarProps { isOpen: boolean @@ -28,6 +32,10 @@ export interface SidebarProps { resetPreviewNode: any previousPreviewNode: any nextPreviewNode: any + openContextMenu: any + scope: Scope + setScope: any + windowWidth: number } const Sidebar = (props: SidebarProps) => { @@ -46,10 +54,15 @@ const Sidebar = (props: SidebarProps) => { resetPreviewNode, previousPreviewNode, nextPreviewNode, + openContextMenu, + scope, + setScope, + windowWidth, } = props const { highlightColor } = useContext(ThemeContext) const [previewRoamNode, setPreviewRoamNode] = useState() + const [sidebarWidth, setSidebarWidth] = usePersistantState('sidebarWidth', 400) useEffect(() => { if (!previewNode?.id) { @@ -67,25 +80,58 @@ const Sidebar = (props: SidebarProps) => { //maybe want to close it when clicking outside, but not sure //const outsideClickRef = useRef(); return ( - - - + { + setSidebarWidth((curr: number) => curr + d.width) + }} + enable={{ + top: false, + right: false, + bottom: false, + left: true, + topRight: false, + bottomRight: false, + bottomLeft: false, + topLeft: false, + }} + minWidth="220px" + maxWidth={windowWidth - 200} + > + - - + { + e.preventDefault() + openContextMenu(previewNode, e) + }} + /> + { + e.preventDefault() + openContextMenu(previewNode, e) + }} + > { {previewRoamNode?.title} - } - aria-label="Close file-viewer" - variant="link" - onClick={onClose} - /> + + } + aria-label="Options" + variant="subtle" + onClick={(e) => { + openContextMenu(previewNode, e, { + left: undefined, + top: 12, + right: -windowWidth + 20, + bottom: undefined, + }) + }} + /> + { borderRadius: 10, backgroundColor: highlightColor, }} - color="black" + color="alt.100" {...props} /> )} @@ -148,13 +204,14 @@ const Sidebar = (props: SidebarProps) => { justification, justificationList, linksByNodeId, + openContextMenu, }} /> - - + + ) } diff --git a/components/Tweaks/BehaviorPanel.tsx b/components/Tweaks/BehaviorPanel.tsx index 651396d..5d61730 100644 --- a/components/Tweaks/BehaviorPanel.tsx +++ b/components/Tweaks/BehaviorPanel.tsx @@ -11,6 +11,7 @@ import { VStack, Text, Box, + Switch, } from '@chakra-ui/react' import React from 'react' import { initialBehavior, initialMouse } from '../config' diff --git a/components/Tweaks/SliderWithInfo.tsx b/components/Tweaks/SliderWithInfo.tsx index f70faae..9d6903a 100644 --- a/components/Tweaks/SliderWithInfo.tsx +++ b/components/Tweaks/SliderWithInfo.tsx @@ -30,7 +30,7 @@ export const SliderWithInfo = ({ const { onChange, label, infoText } = rest const { highlightColor } = useContext(ThemeContext) return ( - + {label} {infoText && } diff --git a/components/Tweaks/index.tsx b/components/Tweaks/index.tsx index c60e670..33f11ee 100644 --- a/components/Tweaks/index.tsx +++ b/components/Tweaks/index.tsx @@ -68,6 +68,7 @@ export const Tweaks = (props: TweakProps) => { tagColors, setTagColors, } = props + const [showTweaks, setShowTweaks] = usePersistantState('showTweaks', false) const { highlightColor, setHighlightColor } = useContext(ThemeContext) @@ -75,12 +76,12 @@ export const Tweaks = (props: TweakProps) => { } onClick={() => setShowTweaks(true)} @@ -88,17 +89,17 @@ export const Tweaks = (props: TweakProps) => { ) : ( { paddingTop={1} > - @@ -124,7 +125,7 @@ export const Tweaks = (props: TweakProps) => { setPhysics(initialPhysics) setBehavior(initialBehavior) }} - variant="none" + variant="subtle" size="sm" /> @@ -132,7 +133,7 @@ export const Tweaks = (props: TweakProps) => { size="sm" icon={} aria-label="Close Tweak Panel" - variant="ghost" + variant="subtle" onClick={() => setShowTweaks(false)} /> diff --git a/components/config.ts b/components/config.ts index e1923f2..fd77ba3 100644 --- a/components/config.ts +++ b/components/config.ts @@ -58,13 +58,13 @@ export const initialVisuals = { nodeOpacity: 1, nodeResolution: 12, labels: 2, - labelScale: 1.5, + labelScale: 1, labelFontSize: 13, labelLength: 40, labelWordWrap: 25, labelLineSpace: 1, highlight: true, - highlightNodeSize: 2, + highlightNodeSize: 1.2, highlightLinkSize: 2, highlightFade: 0.8, highlightAnim: true, @@ -123,6 +123,7 @@ export const initialMouse = { follow: 'never', context: 'right', preview: 'click', + backgroundExitsLocal: false, } export const colorList = [ diff --git a/components/contextmenu.tsx b/components/contextmenu.tsx index 73758a5..bff4861 100644 --- a/components/contextmenu.tsx +++ b/components/contextmenu.tsx @@ -48,20 +48,21 @@ import { BiNetworkChart } from 'react-icons/bi' export default interface ContextMenuProps { background: Boolean - node?: OrgRoamNode + target: OrgRoamNode | null nodeType?: string - coordinates: number[] + coordinates: { [direction: string]: number } handleLocal: (node: OrgRoamNode, add: string) => void menuClose: () => void scope: { nodeIds: string[] } webSocket: any setPreviewNode: any + contextMenuRef: any } export const ContextMenu = (props: ContextMenuProps) => { const { background, - node, + target, nodeType, coordinates, handleLocal, @@ -69,59 +70,65 @@ export const ContextMenu = (props: ContextMenuProps) => { scope, webSocket, setPreviewNode, + contextMenuRef, } = props const { isOpen, onOpen, onClose } = useDisclosure() const copyRef = useRef() return ( <> - - menuClose()}> - - {node && ( - <> - - {node.title} - - - - )} - {scope.nodeIds.length !== 0 && ( - <> - handleLocal(node!, 'add')} icon={}> - Expand local graph at node - - handleLocal(node!, 'replace')} icon={}> - Open local graph for this node - - - )} - {!node?.properties.FILELESS ? ( - } - onClick={() => openNodeInEmacs(node as OrgRoamNode, webSocket)} - > - Open in Emacs + menuClose()}> + + {target && ( + <> + + {target.title} + + + + )} + {scope.nodeIds.length !== 0 && ( + <> + handleLocal(target!, 'add')} icon={}> + Expand local graph at node - ) : ( - } onClick={() => createNodeInEmacs(node, webSocket)}> - Create node + handleLocal(target!, 'replace')} icon={}> + Open local graph for this node - )} - {node?.properties.ROAM_REFS && ( - }>Open in Zotero - )} - {scope.nodeIds.length === 0 && ( - } onClick={() => handleLocal(node!, 'replace')}> - Open local graph - - )} - {/* Doesn't work at the moment + + )} + {!target?.properties?.FILELESS ? ( + } + onClick={() => openNodeInEmacs(target as OrgRoamNode, webSocket)} + > + Open in Emacs + + ) : ( + } onClick={() => createNodeInEmacs(target, webSocket)}> + Create node + + )} + {target?.properties?.ROAM_REFS && ( + }>Open in Zotero + )} + {scope.nodeIds.length === 0 && ( + } onClick={() => handleLocal(target!, 'replace')}> + Open local graph + + )} + {/* Doesn't work at the moment { */} + } + onClick={() => { + setPreviewNode(target) + }} + > + Preview + + {target?.level === 0 && ( } - onClick={() => { - setPreviewNode(node) - }} + closeOnSelect={false} + icon={} + color="red.500" + onClick={onOpen} > - Preview + Permenantly delete note - {node?.level === 0 && ( - } - color="red.500" - onClick={onOpen} - > - Permenantly delete note - - )} - - - + )} + + @@ -180,8 +186,8 @@ export const ContextMenu = (props: ContextMenuProps) => { This will permanently delete your note: - {node?.title} - {node?.level !== 0 && ( + {target?.title} + {target?.level !== 0 && ( 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. @@ -207,7 +213,7 @@ export const ContextMenu = (props: ContextMenuProps) => { ml={3} onClick={() => { console.log('aaaaa') - deleteNodeInEmacs(node!, webSocket) + deleteNodeInEmacs(target!, webSocket) onClose() menuClose() }} -- cgit v1.2.3