mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-24 06:58:48 -05:00
feat: enables expandable labels on nodes
This commit is contained in:
@@ -40,7 +40,7 @@ export const IconSelectionControls = () => {
|
||||
<Stack spacing={2}>
|
||||
<Searchbox value={filter} onChange={setFilter} />
|
||||
<Alert severity="info">
|
||||
You can drag and drop icons below onto the canvas.
|
||||
You can drag and drop items below onto the canvas.
|
||||
</Alert>
|
||||
</Stack>
|
||||
</Section>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Button as MuiButton } from '@mui/material';
|
||||
import { Button as MuiButton, SxProps } from '@mui/material';
|
||||
import {
|
||||
ExpandMore as ReadMoreIcon,
|
||||
ExpandLess as ReadLessIcon
|
||||
@@ -8,9 +8,10 @@ import {
|
||||
interface Props {
|
||||
isExpanded: boolean;
|
||||
onClick: () => void;
|
||||
sx?: SxProps;
|
||||
}
|
||||
|
||||
export const ExpandButton = ({ isExpanded, onClick }: Props) => {
|
||||
export const ExpandButton = ({ isExpanded, onClick, sx }: Props) => {
|
||||
return (
|
||||
<MuiButton
|
||||
sx={{
|
||||
@@ -21,7 +22,8 @@ export const ExpandButton = ({ isExpanded, onClick }: Props) => {
|
||||
fontSize: '0.7em',
|
||||
bottom: 5,
|
||||
right: 5,
|
||||
color: 'common.white'
|
||||
color: 'common.white',
|
||||
...sx
|
||||
}}
|
||||
onClick={onClick}
|
||||
>
|
||||
|
||||
84
src/components/Label/ExpandableLabel.tsx
Normal file
84
src/components/Label/ExpandableLabel.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React, { useState, useRef, useEffect, useMemo } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { useResizeObserver } from 'src/hooks/useResizeObserver';
|
||||
import { Gradient } from 'src/components/Gradient/Gradient';
|
||||
import { ExpandButton } from './ExpandButton';
|
||||
import { Label, Props as LabelProps } from './Label';
|
||||
|
||||
type Props = Omit<LabelProps, 'maxHeight'>;
|
||||
|
||||
const STANDARD_LABEL_HEIGHT = 80;
|
||||
|
||||
export const ExpandableLabel = ({ children, ...rest }: Props) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const contentRef = useRef<HTMLDivElement>();
|
||||
const { observe, size: contentSize } = useResizeObserver();
|
||||
|
||||
useEffect(() => {
|
||||
if (!contentRef.current) return;
|
||||
|
||||
observe(contentRef.current);
|
||||
}, [observe]);
|
||||
|
||||
const containerMaxHeight = useMemo(() => {
|
||||
return isExpanded ? undefined : STANDARD_LABEL_HEIGHT;
|
||||
}, [isExpanded]);
|
||||
|
||||
const isContentTruncated = useMemo(() => {
|
||||
return !isExpanded && contentSize.height >= STANDARD_LABEL_HEIGHT - 10;
|
||||
}, [isExpanded, contentSize.height]);
|
||||
|
||||
useEffect(() => {
|
||||
contentRef.current?.scrollTo({ top: 0 });
|
||||
}, [isExpanded]);
|
||||
|
||||
return (
|
||||
<Label
|
||||
{...rest}
|
||||
maxHeight={containerMaxHeight}
|
||||
maxWidth={isExpanded ? rest.maxWidth * 1.5 : rest.maxWidth}
|
||||
>
|
||||
<Box
|
||||
ref={contentRef}
|
||||
sx={{
|
||||
'&::-webkit-scrollbar': {
|
||||
display: 'none'
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
overflowY: isExpanded ? 'scroll' : 'hidden',
|
||||
maxHeight: containerMaxHeight
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
{isContentTruncated && (
|
||||
<Gradient
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: 50,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{((!isExpanded && isContentTruncated) || isExpanded) && (
|
||||
<ExpandButton
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
m: 0.5
|
||||
}}
|
||||
isExpanded={isExpanded}
|
||||
onClick={() => {
|
||||
setIsExpanded(!isExpanded);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Label>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import { Box, SxProps } from '@mui/material';
|
||||
|
||||
const CONNECTOR_DOT_SIZE = 3;
|
||||
|
||||
interface Props {
|
||||
export interface Props {
|
||||
labelHeight?: number;
|
||||
maxWidth: number;
|
||||
maxHeight?: number;
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, Typography } from '@mui/material';
|
||||
import { PROJECTED_TILE_SIZE, DEFAULT_LABEL_HEIGHT } from 'src/config';
|
||||
import { Box, Typography, Stack } from '@mui/material';
|
||||
import {
|
||||
PROJECTED_TILE_SIZE,
|
||||
DEFAULT_LABEL_HEIGHT,
|
||||
MARKDOWN_EMPTY_VALUE
|
||||
} from 'src/config';
|
||||
import { getTilePosition } from 'src/utils';
|
||||
import { useIcon } from 'src/hooks/useIcon';
|
||||
import { ViewItem } from 'src/types';
|
||||
import { useModelItem } from 'src/hooks/useModelItem';
|
||||
import { Label } from 'src/components/Label/Label';
|
||||
import { ExpandableLabel } from 'src/components/Label/ExpandableLabel';
|
||||
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
|
||||
|
||||
interface Props {
|
||||
node: ViewItem;
|
||||
@@ -26,7 +31,7 @@ export const Node = ({ node, order }: Props) => {
|
||||
const description = useMemo(() => {
|
||||
if (
|
||||
modelItem.description === undefined ||
|
||||
modelItem.description === '<p><br></p>'
|
||||
modelItem.description === MARKDOWN_EMPTY_VALUE
|
||||
)
|
||||
return null;
|
||||
|
||||
@@ -52,16 +57,21 @@ export const Node = ({ node, order }: Props) => {
|
||||
sx={{ position: 'absolute' }}
|
||||
style={{ bottom: PROJECTED_TILE_SIZE.height / 2 }}
|
||||
>
|
||||
<Label
|
||||
<ExpandableLabel
|
||||
maxWidth={250}
|
||||
maxHeight={100}
|
||||
expandDirection="BOTTOM"
|
||||
labelHeight={node.labelHeight ?? DEFAULT_LABEL_HEIGHT}
|
||||
>
|
||||
{modelItem.name && (
|
||||
<Typography fontWeight={600}>{modelItem.name}</Typography>
|
||||
)}
|
||||
</Label>
|
||||
<Stack spacing={1}>
|
||||
{modelItem.name && (
|
||||
<Typography fontWeight={600}>{modelItem.name}</Typography>
|
||||
)}
|
||||
{modelItem.description &&
|
||||
modelItem.description !== MARKDOWN_EMPTY_VALUE && (
|
||||
<MarkdownEditor value={modelItem.description} readOnly />
|
||||
)}
|
||||
</Stack>
|
||||
</ExpandableLabel>
|
||||
</Box>
|
||||
)}
|
||||
{iconComponent && (
|
||||
|
||||
@@ -113,3 +113,4 @@ export const DEFAULT_ICON: Icon = {
|
||||
|
||||
export const DEFAULT_LABEL_HEIGHT = 20;
|
||||
export const PROJECT_BOUNDING_BOX_PADDING = 3;
|
||||
export const MARKDOWN_EMPTY_VALUE = '<p><br></p>';
|
||||
|
||||
Reference in New Issue
Block a user