xinnni's picture
Upload 146 files
f909d7c verified
import React from "react";
import styled from "styled-components";
import { MdLink, MdLinkOff } from "react-icons/md";
import { CustomNodeProps } from "src/containers/Views/GraphView/CustomNode";
import useToggleHide from "src/hooks/useToggleHide";
import { isContentImage } from "src/lib/utils/graph/calculateNodeSize";
import useConfig from "src/store/useConfig";
import useGraph from "src/store/useGraph";
import { TextRenderer } from "./TextRenderer";
import * as Styled from "./styles";
const StyledExpand = styled.button`
pointer-events: all;
display: inline-flex;
align-items: center;
justify-content: center;
color: ${({ theme }) => theme.TEXT_NORMAL};
background: rgba(0, 0, 0, 0.1);
height: 100%;
width: 40px;
border-left: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
&:hover {
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
`;
const StyledTextNodeWrapper = styled.span<{ $hasCollapse: boolean }>`
display: flex;
justify-content: ${({ $hasCollapse }) => ($hasCollapse ? "space-between" : "center")};
align-items: center;
height: 100%;
width: 100%;
`;
const StyledImageWrapper = styled.div`
padding: 5px;
`;
const StyledImage = styled.img`
border-radius: 2px;
object-fit: contain;
background: ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
`;
const Node: React.FC<CustomNodeProps> = ({ node, x, y, hasCollapse = false }) => {
const {
id,
text,
width,
height,
data: { isParent, childrenCount, type },
} = node;
const { validateHiddenNodes } = useToggleHide();
const collapseButtonVisible = useConfig(state => state.collapseButtonVisible);
const childrenCountVisible = useConfig(state => state.childrenCountVisible);
const imagePreviewEnabled = useConfig(state => state.imagePreviewEnabled);
const expandNodes = useGraph(state => state.expandNodes);
const collapseNodes = useGraph(state => state.collapseNodes);
const isExpanded = useGraph(state => state.collapsedParents.includes(id));
const isImage = imagePreviewEnabled && isContentImage(text as string);
const value = JSON.stringify(text).replaceAll('"', "");
const handleExpand = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
if (!isExpanded) collapseNodes(id);
else expandNodes(id);
validateHiddenNodes();
};
return (
<Styled.StyledForeignObject width={width} height={height} x={0} y={0}>
{isImage ? (
<StyledImageWrapper>
<StyledImage src={text as string} width="70" height="70" loading="lazy" />
</StyledImageWrapper>
) : (
<StyledTextNodeWrapper
data-x={x}
data-y={y}
data-key={JSON.stringify(text)}
$hasCollapse={isParent && collapseButtonVisible}
>
<Styled.StyledKey $value={value} $parent={isParent} $type={type}>
<TextRenderer>{value}</TextRenderer>
</Styled.StyledKey>
{isParent && childrenCount > 0 && childrenCountVisible && (
<Styled.StyledChildrenCount>({childrenCount})</Styled.StyledChildrenCount>
)}
{isParent && hasCollapse && collapseButtonVisible && (
<StyledExpand aria-label="Expand" onClick={handleExpand}>
{isExpanded ? <MdLinkOff size={18} /> : <MdLink size={18} />}
</StyledExpand>
)}
</StyledTextNodeWrapper>
)}
</Styled.StyledForeignObject>
);
};
function propsAreEqual(prev: CustomNodeProps, next: CustomNodeProps) {
return (
prev.node.text === next.node.text &&
prev.node.width === next.node.width &&
prev.node.data.childrenCount === next.node.data.childrenCount
);
}
export const TextNode = React.memo(Node, propsAreEqual);