feat: adds image export options to toggle grid and change bg color

This commit is contained in:
Vacharanon
2024-03-27 06:22:27 +07:00
committed by GitHub
parent a9bee06a4d
commit ee7a92d1f3
9 changed files with 145 additions and 12 deletions

43
package-lock.json generated
View File

@@ -19,6 +19,7 @@
"file-saver": "^2.0.5",
"gsap": "^3.11.4",
"immer": "^10.0.2",
"mui-color-input": "^2.0.3",
"paper": "^0.12.17",
"pathfinding": "^0.4.18",
"react-hook-form": "^7.43.2",
@@ -641,6 +642,14 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
"node_modules/@ctrl/tinycolor": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.0.3.tgz",
"integrity": "sha512-e9nEVehVJwkymQpkGhdSNzLT2Lr9UTTby+JePq4Z2SxBbOQjY7pLgSouAaXvfaGQVSAaY0U4eJdwfSDmCbItcw==",
"engines": {
"node": ">=14"
}
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -10860,6 +10869,27 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/mui-color-input": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/mui-color-input/-/mui-color-input-2.0.3.tgz",
"integrity": "sha512-rAd040qQ0Y+8dk4gE8kkCiJ/vCgA0j4vv1quJ43BfORTFE3uHarHj0xY1Vo9CPbojtx1f5vW+CjckYPRIZPIRg==",
"dependencies": {
"@ctrl/tinycolor": "^4.0.3"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material": "^5.0.0",
"@types/react": "^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/multicast-dns": {
"version": "7.2.5",
"resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
@@ -15006,6 +15036,11 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
"@ctrl/tinycolor": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.0.3.tgz",
"integrity": "sha512-e9nEVehVJwkymQpkGhdSNzLT2Lr9UTTby+JePq4Z2SxBbOQjY7pLgSouAaXvfaGQVSAaY0U4eJdwfSDmCbItcw=="
},
"@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -22662,6 +22697,14 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"mui-color-input": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/mui-color-input/-/mui-color-input-2.0.3.tgz",
"integrity": "sha512-rAd040qQ0Y+8dk4gE8kkCiJ/vCgA0j4vv1quJ43BfORTFE3uHarHj0xY1Vo9CPbojtx1f5vW+CjckYPRIZPIRg==",
"requires": {
"@ctrl/tinycolor": "^4.0.3"
}
},
"multicast-dns": {
"version": "7.2.5",
"resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",

View File

@@ -78,6 +78,7 @@
"file-saver": "^2.0.5",
"gsap": "^3.11.4",
"immer": "^10.0.2",
"mui-color-input": "^2.0.3",
"paper": "^0.12.17",
"pathfinding": "^0.4.18",
"react-hook-form": "^7.43.2",

View File

@@ -20,7 +20,8 @@ const App = ({
height = '100%',
onModelUpdated,
enableDebugTools = false,
editorMode = 'EDITABLE'
editorMode = 'EDITABLE',
renderer
}: IsoflowProps) => {
const uiStateActions = useUiStateStore((state) => {
return state.actions;
@@ -71,7 +72,7 @@ const App = ({
transform: 'translateZ(0)'
}}
>
<Renderer />
<Renderer {...renderer} />
<UiOverlay />
</Box>
</>

View File

@@ -0,0 +1,26 @@
import {
MuiColorButtonProps,
MuiColorInput,
MuiColorInputProps
} from 'mui-color-input';
import React from 'react';
import { ColorSwatch } from './ColorSwatch';
interface Props extends Omit<MuiColorInputProps, 'ref'> {}
const ColorButtonElement = ({ bgColor, onClick }: MuiColorButtonProps) => {
return <ColorSwatch hex={bgColor} onClick={onClick} />;
};
export const ColorPicker = ({ value, onChange }: Props) => {
return (
<MuiColorInput
size="small"
variant="standard"
format="hex"
value={value}
onChange={onChange}
InputProps={{ disableUnderline: true, type: 'hidden' }}
Adornment={ColorButtonElement}
/>
);
};

View File

@@ -4,7 +4,7 @@ import { Box, Button } from '@mui/material';
export type Props = {
hex: string;
isActive?: boolean;
onClick: () => void;
onClick: React.MouseEventHandler<HTMLButtonElement> | undefined;
};
export const ColorSwatch = ({ hex, onClick, isActive }: Props) => {

View File

@@ -12,7 +12,10 @@ import {
Box,
Button,
Stack,
Alert
Alert,
Checkbox,
FormControlLabel,
Typography
} from '@mui/material';
import { useModelStore } from 'src/stores/modelStore';
import {
@@ -27,6 +30,8 @@ import { useDiagramUtils } from 'src/hooks/useDiagramUtils';
import { useUiStateStore } from 'src/stores/uiStateStore';
import { Isoflow } from 'src/Isoflow';
import { Loader } from 'src/components/Loader/Loader';
import { customVars } from 'src/styles/theme';
import { ColorPicker } from 'src/components/ColorSelector/ColorPicker';
interface Props {
quality?: number;
@@ -87,6 +92,22 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
downloadFileUtil(data, generateGenericFilename('png'));
}, [imageData]);
const [showGrid, setShowGrid] = useState(false);
const handleShowGridChange = (checked: boolean) => {
setShowGrid(checked);
};
const [backgroundColor, setBackgroundColor] = useState<string>(
customVars.customPalette.diagramBg
);
const handleBackgroundColorChange = (color: string) => {
setBackgroundColor(color);
};
useEffect(() => {
setImageData(undefined);
}, [showGrid, backgroundColor]);
return (
<Dialog open onClose={onClose}>
<DialogTitle>Export as image</DialogTitle>
@@ -131,6 +152,10 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
fitToView: true,
view: currentView
}}
renderer={{
showGrid,
backgroundColor
}}
/>
</Box>
</Box>
@@ -148,9 +173,8 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
</Box>
</>
)}
{imageData && (
<Stack alignItems="center" spacing={2}>
<Stack alignItems="center" spacing={2}>
{imageData && (
<Box
component="img"
sx={{
@@ -162,6 +186,37 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
src={imageData}
alt="preview"
/>
)}
<Box sx={{ width: '100%' }}>
<Box component="fieldset">
<Typography variant="caption" component="legend">
Options
</Typography>
<FormControlLabel
label="Show grid"
control={
<Checkbox
size="small"
checked={showGrid}
onChange={(event) => {
handleShowGridChange(event.target.checked);
}}
/>
}
/>
<FormControlLabel
label="Background color"
control={
<ColorPicker
value={backgroundColor}
onChange={handleBackgroundColorChange}
/>
}
/>
</Box>
</Box>
{imageData && (
<Stack sx={{ width: '100%' }} alignItems="flex-end">
<Stack direction="row" spacing={2}>
<Button variant="text" onClick={onClose}>
@@ -170,8 +225,8 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
<Button onClick={downloadFile}>Download as PNG</Button>
</Stack>
</Stack>
</Stack>
)}
)}
</Stack>
{exportError && (
<Alert severity="error">Could not export image</Alert>

View File

@@ -13,8 +13,9 @@ import { SizeIndicator } from 'src/components/DebugUtils/SizeIndicator';
import { SceneLayer } from 'src/components/SceneLayer/SceneLayer';
import { TransformControlsManager } from 'src/components/TransformControlsManager/TransformControlsManager';
import { useScene } from 'src/hooks/useScene';
import { RendererProps } from 'src/types/rendererProps';
export const Renderer = () => {
export const Renderer = ({ showGrid, backgroundColor }: RendererProps) => {
const containerRef = useRef<HTMLDivElement>();
const interactionsRef = useRef<HTMLDivElement>();
const enableDebugTools = useUiStateStore((state) => {
@@ -47,7 +48,7 @@ export const Renderer = () => {
height: '100%',
zIndex: 0,
bgcolor: (theme) => {
return theme.customVars.customPalette.diagramBg;
return backgroundColor ?? theme.customVars.customPalette.diagramBg;
}
}}
>
@@ -63,7 +64,7 @@ export const Renderer = () => {
left: 0
}}
>
<Grid />
{showGrid && <Grid />}
</Box>
{mode.showCursor && (
<SceneLayer>

View File

@@ -1,5 +1,6 @@
import type { EditorModeEnum, MainMenuOptions } from './common';
import type { Model } from './model';
import type { RendererProps } from './rendererProps';
export type InitialData = Model & {
fitToView?: boolean;
@@ -14,4 +15,5 @@ export interface IsoflowProps {
height?: number | string;
enableDebugTools?: boolean;
editorMode?: keyof typeof EditorModeEnum;
renderer?: RendererProps;
}

View File

@@ -0,0 +1,4 @@
export interface RendererProps {
showGrid?: boolean;
backgroundColor?: string;
}