summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/config.ts65
-rw-r--r--components/tweaks.tsx471
2 files changed, 536 insertions, 0 deletions
diff --git a/components/config.ts b/components/config.ts
new file mode 100644
index 0000000..41d5345
--- /dev/null
+++ b/components/config.ts
@@ -0,0 +1,65 @@
+import { Easing } from '@tweenjs/tween.js'
+
+export 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',
+}
+
+export const initialFilter = {
+ orphans: false,
+ parents: true,
+ tags: [],
+ nodes: [],
+ links: [],
+ date: [],
+}
+
+function 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
+}
diff --git a/components/tweaks.tsx b/components/tweaks.tsx
new file mode 100644
index 0000000..a082306
--- /dev/null
+++ b/components/tweaks.tsx
@@ -0,0 +1,471 @@
+import { RepeatClockIcon, ChevronDownIcon, SettingsIcon, InfoOutlineIcon } from '@chakra-ui/icons'
+import {
+ Accordion,
+ AccordionButton,
+ AccordionIcon,
+ AccordionItem,
+ AccordionPanel,
+ Box,
+ Button,
+ CloseButton,
+ Flex,
+ IconButton,
+ Menu,
+ MenuButton,
+ MenuItem,
+ MenuList,
+ Select,
+ Slider,
+ SliderFilledTrack,
+ SliderThumb,
+ SliderTrack,
+ StackDivider,
+ Switch,
+ Text,
+ Tooltip,
+ VStack,
+} from '@chakra-ui/react'
+import Scrollbars from 'react-custom-scrollbars-2'
+import { initialPhysics, initialFilter } from './config'
+
+export interface TweakProps {
+ physics: typeof initialPhysics
+ setPhysics: any
+ threeDim: boolean
+ setThreeDim: (newValue: 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={opt}>
+ {opt}
+ </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 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>
+ )
+}