mirror of
https://github.com/markmanx/isoflow.git
synced 2025-02-08 12:27:53 +00:00
feat: implements readmore on node description overflow
This commit is contained in:
parent
ee3306b691
commit
f9536c9cb7
9 changed files with 98 additions and 38 deletions
18
src/components/Gradient/Gradient.tsx
Normal file
18
src/components/Gradient/Gradient.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
import { Box, SxProps } from '@mui/material';
|
||||
|
||||
interface Props {
|
||||
sx?: SxProps;
|
||||
}
|
||||
|
||||
export const Gradient = ({ sx }: Props) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 5%, rgba(255,255,255,0) 100%)',
|
||||
...sx
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Slider, Box } from '@mui/material';
|
||||
import { Slider, Box, TextField } from '@mui/material';
|
||||
import { Node } from 'src/types';
|
||||
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
|
||||
import { DeleteButton } from '../../components/DeleteButton';
|
||||
|
@ -15,13 +15,22 @@ export const NodeSettings = ({ node, onUpdate, onDelete }: Props) => {
|
|||
return (
|
||||
<>
|
||||
<Section title="Label">
|
||||
<MarkdownEditor
|
||||
<TextField
|
||||
value={node.label}
|
||||
onChange={(text) => {
|
||||
onChange={(e) => {
|
||||
const text = e.target.value as string;
|
||||
if (node.label !== text) onUpdate({ label: text });
|
||||
}}
|
||||
/>
|
||||
</Section>
|
||||
<Section title="Description">
|
||||
<MarkdownEditor
|
||||
value={node.description}
|
||||
onChange={(text) => {
|
||||
if (node.description !== text) onUpdate({ description: text });
|
||||
}}
|
||||
/>
|
||||
</Section>
|
||||
{node.label && (
|
||||
<Section title="Label height">
|
||||
<Slider
|
||||
|
|
|
@ -3,7 +3,7 @@ import ReactQuill from 'react-quill';
|
|||
import { Box } from '@mui/material';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
readOnly?: boolean;
|
||||
height?: number;
|
||||
|
@ -55,7 +55,7 @@ export const MarkdownEditor = ({
|
|||
>
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={value}
|
||||
value={value ?? ''}
|
||||
readOnly={readOnly}
|
||||
onChange={onChange}
|
||||
formats={tools}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import React, { useEffect, useRef, useMemo } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { MoreHoriz as ReadMoreIcon } from '@mui/icons-material';
|
||||
import { useResizeObserver } from 'src/hooks/useResizeObserver';
|
||||
import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { useTileSize } from 'src/hooks/useTileSize';
|
||||
import { Gradient } from 'src/components/Gradient/Gradient';
|
||||
|
||||
const MAX_LABEL_HEIGHT = 125;
|
||||
|
||||
interface Props {
|
||||
labelHeight: number;
|
||||
|
@ -66,16 +70,48 @@ export const LabelContainer = ({
|
|||
position: 'absolute',
|
||||
bgcolor: 'common.white',
|
||||
border: '1px solid',
|
||||
borderColor: 'grey.500',
|
||||
borderColor: 'grey.400',
|
||||
borderRadius: 2,
|
||||
left: -contentSize.width * 0.5,
|
||||
top: -(contentSize.height + labelHeight + yOffset),
|
||||
py: 1,
|
||||
px: 1.5,
|
||||
overflow: 'hidden'
|
||||
overflow: 'hidden',
|
||||
maxHeight: MAX_LABEL_HEIGHT
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
{contentSize.height >= MAX_LABEL_HEIGHT - 10 && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
height: 50,
|
||||
width: '100%',
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}}
|
||||
>
|
||||
<Gradient
|
||||
sx={{ position: 'absolute', width: '100%', height: '100%' }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
px: 0.5,
|
||||
py: 0,
|
||||
height: 'auto',
|
||||
minWidth: 0,
|
||||
fontSize: '0.7em',
|
||||
bottom: 5,
|
||||
right: 5,
|
||||
color: 'common.white'
|
||||
}}
|
||||
>
|
||||
<ReadMoreIcon sx={{ color: 'common.white' }} />
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const MarkdownLabel = ({ label }: Props) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
maxWidth: 200,
|
||||
minWidth: 100,
|
||||
maxHeight: 150
|
||||
}}
|
||||
>
|
||||
<MarkdownEditor readOnly value={label} />
|
||||
</Box>
|
||||
);
|
||||
};
|
|
@ -1,11 +1,11 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { Box, Typography, useTheme } from '@mui/material';
|
||||
import { Node as NodeI, TileOriginEnum } from 'src/types';
|
||||
import { useTileSize } from 'src/hooks/useTileSize';
|
||||
import { useGetTilePosition } from 'src/hooks/useGetTilePosition';
|
||||
import { useIcon } from 'src/hooks/useIcon';
|
||||
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
|
||||
import { LabelContainer } from './LabelContainer';
|
||||
import { MarkdownLabel } from './LabelTypes/MarkdownLabel';
|
||||
|
||||
interface Props {
|
||||
node: NodeI;
|
||||
|
@ -13,6 +13,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export const Node = ({ node, order }: Props) => {
|
||||
const theme = useTheme();
|
||||
const { projectedTileSize } = useTileSize();
|
||||
const { getTilePosition } = useGetTilePosition();
|
||||
const { iconComponent } = useIcon(node.icon);
|
||||
|
@ -24,11 +25,12 @@ export const Node = ({ node, order }: Props) => {
|
|||
});
|
||||
}, [node.tile, getTilePosition]);
|
||||
|
||||
const label = useMemo(() => {
|
||||
if (node.label === undefined || node.label === '<p><br></p>') return null;
|
||||
const description = useMemo(() => {
|
||||
if (node.description === undefined || node.description === '<p><br></p>')
|
||||
return null;
|
||||
|
||||
return node.label;
|
||||
}, [node.label]);
|
||||
return node.description;
|
||||
}, [node.description]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
@ -44,7 +46,7 @@ export const Node = ({ node, order }: Props) => {
|
|||
top: position.y
|
||||
}}
|
||||
>
|
||||
{label && (
|
||||
{(node.label || description) && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute'
|
||||
|
@ -57,7 +59,19 @@ export const Node = ({ node, order }: Props) => {
|
|||
}}
|
||||
/>
|
||||
<LabelContainer labelHeight={node.labelHeight} connectorDotSize={3}>
|
||||
<MarkdownLabel label={label} />
|
||||
<Typography fontWeight={600}>{node.label}</Typography>
|
||||
{description && (
|
||||
<Box sx={{ pt: 0.2, width: 180 }}>
|
||||
<MarkdownEditor
|
||||
readOnly
|
||||
value={node.description}
|
||||
styles={{
|
||||
color: theme.palette.text.secondary,
|
||||
fontSize: '0.8em'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</LabelContainer>
|
||||
</Box>
|
||||
)}
|
||||
|
|
|
@ -29,7 +29,8 @@ export interface Node {
|
|||
id: string;
|
||||
type: SceneItemTypeEnum.NODE;
|
||||
icon: string;
|
||||
label: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
labelHeight: number;
|
||||
tile: Coords;
|
||||
isSelected: boolean;
|
||||
|
|
|
@ -40,6 +40,7 @@ export const nodeInputToNode = (nodeInput: NodeInput): Node => {
|
|||
type: SceneItemTypeEnum.NODE,
|
||||
id: nodeInput.id,
|
||||
label: nodeInput.label ?? NODE_DEFAULTS.label,
|
||||
description: nodeInput.description,
|
||||
labelHeight: nodeInput.labelHeight ?? NODE_DEFAULTS.labelHeight,
|
||||
icon: nodeInput.icon,
|
||||
tile: nodeInput.tile,
|
||||
|
@ -215,6 +216,7 @@ export const nodeToNodeInput = (node: Node): NodeInput => {
|
|||
id: node.id,
|
||||
tile: node.tile,
|
||||
label: node.label,
|
||||
description: node.description,
|
||||
labelHeight: node.labelHeight,
|
||||
icon: node.icon
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ export const iconInput = z.object({
|
|||
export const nodeInput = z.object({
|
||||
id: z.string(),
|
||||
label: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
labelHeight: z.number().optional(),
|
||||
icon: z.string(),
|
||||
tile: coords
|
||||
|
|
Loading…
Reference in a new issue