summaryrefslogtreecommitdiff
path: root/pages/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'pages/index.tsx')
-rw-r--r--pages/index.tsx548
1 files changed, 3 insertions, 545 deletions
diff --git a/pages/index.tsx b/pages/index.tsx
index 22adb3f..d39db81 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -10,48 +10,18 @@ import { OrgRoamGraphReponse, OrgRoamLink, OrgRoamNode } from '../api'
import { GraphData, NodeObject } from 'force-graph'
import { useWindowSize } from '@react-hook/window-size'
-import { Scrollbars } from 'react-custom-scrollbars-2'
-import { Easing } from '@tweenjs/tween.js'
import { useAnimation } from '@lilib/hooks'
import {
- Accordion,
- AccordionButton,
- AccordionItem,
- AccordionIcon,
- AccordionPanel,
- Text,
- Heading,
- VStack,
- StackDivider,
Button,
- CloseButton,
- Slider,
- SliderThumb,
- SliderTrack,
- SliderFilledTrack,
- Switch,
- FormControl,
- FormLabel,
Box,
- Container,
- Icon,
IconButton,
- Tooltip,
- Menu,
- MenuList,
- MenuButton,
- MenuItem,
- MenuGroup,
- MenuDivider,
- MenuOptionGroup,
- MenuItemOption,
- Flex,
useTheme,
- Select,
} from '@chakra-ui/react'
-import { InfoOutlineIcon, RepeatClockIcon, ChevronDownIcon, SettingsIcon } from '@chakra-ui/icons'
+import { SettingsIcon } from '@chakra-ui/icons'
+import { initialPhysics, initialFilter } from '../components/config'
+import { Tweaks } from '../components/tweaks'
// react-force-graph fails on import when server-rendered
// https://github.com/vasturiano/react-force-graph/issues/155
@@ -72,68 +42,6 @@ export type Scope = {
nodeIds: string[]
}
-const getAlgos = (option?: boolean) => {
- const options: string[] = []
- const algorithms: { [name: string]: (percent: number) => number } = {}
- for (let type in Easing) {
- for (let mode in (Easing as any)[type]) {
- let name = type + mode
- if (name === 'LinearNone') {
- name = 'Linear'
- }
- option ? options.push(name) : (algorithms[name] = (Easing as any)[type][mode])
- }
- }
- return option ? options : algorithms
-}
-const initialPhysics = {
- enabled: true,
- charge: -350,
- collision: true,
- collisionStrength: 0,
- linkStrength: 0.1,
- linkIts: 1,
- particles: false,
- particlesNumber: 0,
- particlesWidth: 4,
- linkOpacity: 0.4,
- linkWidth: 1,
- nodeRel: 4,
- labels: true,
- labelScale: 1.5,
- alphaDecay: 0.02,
- alphaTarget: 0,
- alphaMin: 0,
- velocityDecay: 0.25,
- gravity: 0.5,
- gravityOn: true,
- colorful: true,
- galaxy: true,
- ticks: 1,
- hover: 'highlight',
- click: 'select',
- doubleClick: 'local',
- iterations: 0,
- highlight: true,
- highlightNodeSize: 2,
- highlightLinkSize: 2,
- highlightAnim: false,
- animationSpeed: 250,
- algorithms: getAlgos(false),
- algorithmOptions: getAlgos(true),
- algorithmName: 'CubicOut',
- orphans: false,
- follow: 'Local',
-}
-
-const initialFilter = {
- orphans: false,
- parents: true,
- tags: [],
- nodes: [],
- links: [],
- date: [],
-}
export default function Home() {
// only render on the client
const [showPage, setShowPage] = useState(false)
@@ -255,456 +163,6 @@ export function GraphPage() {
)
}
-export interface InfoTooltipProps {
- infoText?: string | boolean
-}
-export const InfoTooltip = (props: InfoTooltipProps) => {
- const { infoText } = props
- return (
- <Box paddingLeft="1">
- <Tooltip label={infoText} placement="top" color="gray.100" bg="gray.800" hasArrow>
- <InfoOutlineIcon />
- </Tooltip>
- </Box>
- )
-}
-export interface SliderWithInfoProps {
- min?: number
- max?: number
- step?: number
- value: number
- onChange: (arg0: number) => void
- label: string
- infoText?: string
-}
-export const SliderWithInfo = ({
- min = 0,
- max = 10,
- step = 0.1,
- value = 1,
- ...rest
-}: SliderWithInfoProps) => {
- const { onChange, label, infoText } = rest
- return (
- <Box>
- <Box display="flex" alignItems="flex-end">
- <Text>{label}</Text>
- {infoText && <InfoTooltip infoText={infoText} />}
- </Box>
- <Slider
- value={value}
- onChange={onChange}
- min={min}
- max={max}
- step={step}
- colorScheme="purple"
- >
- <SliderTrack>
- <SliderFilledTrack />
- </SliderTrack>
- <Tooltip label={value.toFixed(1)}>
- <SliderThumb />
- </Tooltip>
- </Slider>
- </Box>
- )
-}
-
-export interface EnableSectionProps {
- label: string
- value: boolean | number
- onChange: () => void
- infoText?: string
- children: React.ReactNode
-}
-
-export const EnableSection = (props: EnableSectionProps) => {
- const { value, onChange, label, infoText, children } = props
- return (
- <Box>
- <Box display="flex" justifyContent="space-between">
- <Box display="flex" alignItems="center">
- <Text>{label}</Text>
- {infoText && <InfoTooltip infoText={infoText} />}
- </Box>
- <Switch isChecked={!!value} onChange={onChange} colorScheme="purple" />
- </Box>
- {value && children}
- </Box>
- )
-}
-
-export interface DropDownMenuProps {
- textArray: string[]
- onClickArray: any
- displayValue: string
-}
-
-export const DropDownMenu = (props: DropDownMenuProps) => {
- const { textArray, onClickArray, displayValue } = props
- return (
- <Menu>
- <MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
- {displayValue}
- </MenuButton>
- <MenuList>
- {textArray.map((option, i) => {
- ;<MenuItem onClick={onClickArray[i]}> {option} </MenuItem>
- })}
- </MenuList>
- </Menu>
- )
-}
-/* style={{
- * position: "absolute",
- * zIndex: 2000,
- * width: 400,
- * maxHeight: "70%",
- * background: "alt.100",
- * marginTop: "2%",
- * marginLeft: "2%"
- * }} */
-export interface TweakProps {
- physics: typeof initialPhysics
- setPhysics: any
- threeDim: boolean
- setThreedim: (boolean) => void
- filter: typeof initialFilter
- setFilter: any
- onClose: () => void
-}
-export const Tweaks = (props: TweakProps) => {
- const { physics, setPhysics, threeDim, filter, setFilter, onClose } = props
- return (
- <Box
- zIndex="overlay"
- position="absolute"
- bg="alt.100"
- w="xs"
- marginTop="2%"
- marginLeft="2%"
- borderRadius="md"
- maxH={650}
- paddingBottom={5}
- //overflowY="scroll"
- >
- <Box display="flex" justifyContent="flex-end">
- <Tooltip label="Reset settings to defaults">
- <IconButton
- aria-label="Reset Defaults"
- icon={<RepeatClockIcon />}
- onClick={() => setPhysics(initialPhysics)}
- colorScheme="purple"
- />
- </Tooltip>
- <CloseButton onClick={onClose} />
- </Box>
- <Scrollbars
- autoHeight
- autoHeightMax={600}
- autoHide
- renderThumbVertical={({ style, ...props }) => (
- <Box
- {...props}
- style={{
- ...style,
- borderRadius: 10,
- }}
- bg="purple.500"
- />
- )}
- >
- <Accordion allowMultiple allowToggle>
- <AccordionItem>
- <AccordionButton>
- <AccordionIcon />
- <Text>Filter</Text>
- </AccordionButton>
- <AccordionPanel>
- <Flex justifyContent="space-between">
- <Text>Kill orphans</Text>
- <Switch
- colorScheme="purple"
- onChange={() => {
- setFilter({ ...filter, orphans: !filter.orphans })
- }}
- isChecked={filter.orphans}
- ></Switch>
- </Flex>
- <Flex justifyContent="space-between">
- <Text>Link nodes with parent file</Text>
- <Switch
- colorScheme="purple"
- onChange={() => {
- setFilter({ ...filter, parents: !filter.parents })
- }}
- isChecked={filter.parents}
- ></Switch>
- </Flex>
- </AccordionPanel>
- </AccordionItem>
- <AccordionItem>
- <AccordionButton display="flex" justifyContent="space-between">
- <Box display="flex">
- <AccordionIcon />
- <Text>Physics</Text>
- </Box>
- <Switch
- id="physicsOn"
- onChange={() => setPhysics({ ...physics, enabled: !physics.enabled })}
- isChecked={physics.enabled}
- colorScheme="purple"
- />
- </AccordionButton>
- <AccordionPanel>
- <VStack
- spacing={2}
- justifyContent="flex-start"
- divider={<StackDivider borderColor="gray.200" />}
- align="stretch"
- >
- <EnableSection
- label="Gravity"
- value={physics.gravityOn}
- onChange={() => setPhysics({ ...physics, gravityOn: !physics.gravityOn })}
- >
- <SliderWithInfo
- label="Strength"
- value={physics.gravity * 10}
- onChange={(v) => setPhysics({ ...physics, gravity: v / 10 })}
- />
- </EnableSection>
- <SliderWithInfo
- value={-physics.charge / 100}
- onChange={(value) => setPhysics({ ...physics, charge: -100 * value })}
- label="Repulsive Force"
- />
- <EnableSection
- label="Collision"
- infoText="Perfomance sap, disable if slow"
- value={physics.collision}
- onChange={() => setPhysics({ ...physics, collision: !physics.collision })}
- >
- <SliderWithInfo
- value={physics.collisionStrength * 10}
- onChange={(value) => setPhysics({ ...physics, collisionStrength: value / 10 })}
- label="Strength"
- />
- </EnableSection>
- <SliderWithInfo
- value={physics.linkStrength * 5}
- onChange={(value) => setPhysics({ ...physics, linkStrength: value / 5 })}
- label="Link Force"
- />
- <SliderWithInfo
- label="Link Iterations"
- value={physics.linkIts}
- onChange={(value) => setPhysics({ ...physics, linkIts: value })}
- min={0}
- max={6}
- step={1}
- infoText="How many links down the line the physics of a single node affects (Slow)"
- />
- <SliderWithInfo
- label="Viscosity"
- value={physics.velocityDecay * 10}
- onChange={(value) => setPhysics({ ...physics, velocityDecay: value / 10 })}
- />
- </VStack>
- <Box>
- <Accordion allowToggle>
- <AccordionItem>
- <AccordionButton>
- <Text>Advanced</Text>
- <AccordionIcon />
- </AccordionButton>
- <AccordionPanel>
- <VStack
- spacing={2}
- justifyContent="flex-start"
- divider={<StackDivider borderColor="gray.200" />}
- align="stretch"
- >
- <SliderWithInfo
- label="Iterations per tick"
- min={1}
- max={10}
- step={1}
- value={physics.iterations}
- onChange={(v) => setPhysics({ ...physics, iterations: v })}
- infoText="Number of times the physics simulation iterates per simulation step"
- />
- <SliderWithInfo
- label="Stabilization rate"
- value={physics.alphaDecay * 50}
- onChange={(value) => setPhysics({ ...physics, alphaDecay: value / 50 })}
- />
- </VStack>
- </AccordionPanel>
- </AccordionItem>
- </Accordion>
- </Box>
- {/* </VStack> */}
- </AccordionPanel>
- </AccordionItem>
- <AccordionItem>
- <AccordionButton>
- <AccordionIcon />
- Visual
- </AccordionButton>
- <AccordionPanel>
- <VStack
- spacing={2}
- justifyContent="flex-start"
- divider={<StackDivider borderColor="gray.200" />}
- align="stretch"
- >
- <EnableSection
- label="Colors"
- onChange={() => setPhysics({ ...physics, colorful: !physics.colorful })}
- value={physics.colorful}
- >
- <Text>Child</Text>
- </EnableSection>
- <SliderWithInfo
- label="Node size"
- value={physics.nodeRel}
- onChange={(value) => setPhysics({ ...physics, nodeRel: value })}
- />
- <SliderWithInfo
- label="Link width"
- value={physics.linkWidth}
- onChange={(value) => setPhysics({ ...physics, linkWidth: value })}
- />
- <EnableSection
- label="Labels"
- value={physics.labels}
- onChange={() => setPhysics({ ...physics, labels: !physics.labels })}
- >
- <SliderWithInfo
- label="Label Appearance Scale"
- value={physics.labelScale * 5}
- onChange={(value) => setPhysics({ ...physics, labelScale: value / 5 })}
- />
- </EnableSection>
- <EnableSection
- label="Directional Particles"
- value={physics.particles}
- onChange={() => setPhysics({ ...physics, particles: !physics.particles })}
- >
- <SliderWithInfo
- label="Particle Number"
- value={physics.particlesNumber}
- max={5}
- step={1}
- onChange={(value) => setPhysics({ ...physics, particlesNumber: value })}
- />
- <SliderWithInfo
- label="Particle Size"
- value={physics.particlesWidth}
- onChange={(value) => setPhysics({ ...physics, particlesWidth: value })}
- />
- </EnableSection>
- <EnableSection
- label="Highlight Animation"
- onChange={() => {
- setPhysics({ ...physics, highlightAnim: !physics.highlightAnim })
- }}
- value={physics.highlightAnim}
- >
- <SliderWithInfo
- label="Animation speed"
- onChange={(v) => setPhysics({ ...physics, animationSpeed: v })}
- value={physics.animationSpeed}
- infoText="Slower speed has a chance of being buggy"
- min={50}
- max={1000}
- step={10}
- />
- <Select
- placeholder={physics.algorithmName}
- onChange={(v) => {
- setPhysics({ ...physics, algorithmName: v.target.value })
- }}
- >
- {physics.algorithmOptions.map((opt, i) => (
- <option key={i} value={physics.algorithmOptions[i]}>
- {physics.algorithmOptions[i]}
- </option>
- ))}
- </Select>
- {/* <DropDownMenu
- displayValue={physics.algorithmName}
- textArray={physics.algorithmOptions}
- onClickArray={physics.algorithmOptions.map((option) =>
- setPhysics({ ...physics, algorithmName: { option } }),
- )}
- /> */}
- </EnableSection>
- <EnableSection
- label="Highlight"
- onChange={() => setPhysics({ ...physics, highlight: !physics.highlight })}
- value={physics.highlight}
- >
- <SliderWithInfo
- label="Highlight Link Thickness Multiplier"
- value={physics.highlightLinkSize}
- onChange={(value) => setPhysics({ ...physics, highlightLinkSize: value })}
- />
- <SliderWithInfo
- label="Highlight Node Size Multiplier"
- value={physics.highlightNodeSize}
- onChange={(value) => setPhysics({ ...physics, highlightNodeSize: value })}
- />
- <Flex justifyContent="space-between">
- <Text> Highlight node color </Text>
- </Flex>
- <Flex justifyContent="space-between">
- <Text> Highlight link color </Text>
- </Flex>
- </EnableSection>
- </VStack>
- </AccordionPanel>
- </AccordionItem>
- <AccordionItem>
- <AccordionButton>
- <AccordionIcon />
- Behavior
- </AccordionButton>
- <AccordionPanel>
- <VStack
- spacing={2}
- justifyContent="flex-start"
- divider={<StackDivider borderColor="gray.200" />}
- align="stretch"
- >
- <Box display="flex" justifyContent="space-between" alignItems="center">
- <Text>Hover Higlight</Text>
- <Menu>
- <MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
- {physics.hover}
- </MenuButton>
- <MenuList>
- <MenuItem>Off</MenuItem>
- <MenuItem>On</MenuItem>
- </MenuList>
- </Menu>
- </Box>
- <Box display="flex" justifyContent="space-between">
- <Text>Click</Text>
- </Box>
- <Box display="flex" justifyContent="space-between">
- <Text>Double-click</Text>
- </Box>
- </VStack>
- </AccordionPanel>
- </AccordionItem>
- </Accordion>
- </Scrollbars>
- </Box>
- )
-}
-
export interface GraphProps {
nodeById: NodeById
linksByNodeId: LinksByNodeId