chore: image edit ux
This commit is contained in:
@@ -19,10 +19,11 @@ const AutoImage: React.FC<
|
||||
height: number | string;
|
||||
width?: number | string;
|
||||
autoSize?: boolean;
|
||||
preview?: boolean;
|
||||
onLoad?: () => void;
|
||||
}
|
||||
> = (props) => {
|
||||
const { height = 100, width: w, autoSize, ...rest } = props;
|
||||
const { height = 100, width: w, autoSize, preview = true, ...rest } = props;
|
||||
const [width, setWidth] = useState(w || 0);
|
||||
const [isError, setIsError] = useState(false);
|
||||
|
||||
@@ -88,35 +89,37 @@ const AutoImage: React.FC<
|
||||
onLoad={handleImgLoad}
|
||||
fallback={fallbackImg}
|
||||
crossOrigin="anonymous"
|
||||
preview={{
|
||||
mask: <EyeOutlined />,
|
||||
toolbarRender: (
|
||||
_,
|
||||
{
|
||||
transform: { scale },
|
||||
actions: {
|
||||
onFlipY,
|
||||
onFlipX,
|
||||
onRotateLeft,
|
||||
onRotateRight,
|
||||
onZoomOut,
|
||||
onZoomIn,
|
||||
onReset
|
||||
preview={
|
||||
preview ?? {
|
||||
mask: <EyeOutlined />,
|
||||
toolbarRender: (
|
||||
_,
|
||||
{
|
||||
transform: { scale },
|
||||
actions: {
|
||||
onFlipY,
|
||||
onFlipX,
|
||||
onRotateLeft,
|
||||
onRotateRight,
|
||||
onZoomOut,
|
||||
onZoomIn,
|
||||
onReset
|
||||
}
|
||||
}
|
||||
}
|
||||
) => (
|
||||
<Space size={12} className="toolbar-wrapper">
|
||||
<DownloadOutlined onClick={onDownload} />
|
||||
<SwapOutlined rotate={90} onClick={onFlipY} />
|
||||
<SwapOutlined onClick={onFlipX} />
|
||||
<RotateLeftOutlined onClick={onRotateLeft} />
|
||||
<RotateRightOutlined onClick={onRotateRight} />
|
||||
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
|
||||
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
|
||||
<UndoOutlined onClick={onReset} />
|
||||
</Space>
|
||||
)
|
||||
}}
|
||||
) => (
|
||||
<Space size={12} className="toolbar-wrapper">
|
||||
<DownloadOutlined onClick={onDownload} />
|
||||
<SwapOutlined rotate={90} onClick={onFlipY} />
|
||||
<SwapOutlined onClick={onFlipX} />
|
||||
<RotateLeftOutlined onClick={onRotateLeft} />
|
||||
<RotateRightOutlined onClick={onRotateRight} />
|
||||
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
|
||||
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
|
||||
<UndoOutlined onClick={onReset} />
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
.img-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.img-wrapper .auto-image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.img-wrapper .progress-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.progress-square {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.progress-square-bg {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.progress-square-fg {
|
||||
fill: none;
|
||||
stroke-linecap: square;
|
||||
stroke-dasharray: 400;
|
||||
stroke-dashoffset: 400;
|
||||
transition: stroke-dashoffset 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
position: absolute;
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -8,6 +8,13 @@
|
||||
border-radius: var(--border-radius-base);
|
||||
overflow: hidden;
|
||||
|
||||
.progress-wrapper {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.img {
|
||||
display: flex;
|
||||
width: auto;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||
import { Progress } from 'antd';
|
||||
import { Progress, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import ResizeObserver from 'rc-resize-observer';
|
||||
import React, { useCallback } from 'react';
|
||||
import AutoImage from './index';
|
||||
import './single-image.less';
|
||||
|
||||
interface SingleImageProps {
|
||||
loading?: boolean;
|
||||
width?: number;
|
||||
@@ -15,17 +14,23 @@ interface SingleImageProps {
|
||||
maxWidth?: number;
|
||||
dataUrl: string;
|
||||
uid: number;
|
||||
preview?: boolean;
|
||||
autoSize?: boolean;
|
||||
onDelete: (uid: number) => void;
|
||||
onClick?: (item: any) => void;
|
||||
autoBgColor?: boolean;
|
||||
editable?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
progressType?: 'line' | 'circle' | 'dashboard';
|
||||
progressColor?: string;
|
||||
progressWidth?: number;
|
||||
}
|
||||
|
||||
const SingleImage: React.FC<SingleImageProps> = (props) => {
|
||||
const {
|
||||
editable,
|
||||
onDelete: handleOnDelete,
|
||||
onClick,
|
||||
autoSize,
|
||||
uid,
|
||||
loading,
|
||||
@@ -36,10 +41,13 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
|
||||
maxWidth,
|
||||
dataUrl,
|
||||
style,
|
||||
autoBgColor
|
||||
autoBgColor,
|
||||
progressColor = 'var(--ant-color-primary)',
|
||||
progressWidth = 2,
|
||||
preview = true,
|
||||
progressType = 'dashboard'
|
||||
} = props;
|
||||
|
||||
const [color, setColor] = React.useState({});
|
||||
const imgWrapper = React.useRef<HTMLSpanElement>(null);
|
||||
const [imgSize, setImgSize] = React.useState({
|
||||
width: width,
|
||||
@@ -50,6 +58,10 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
|
||||
return loading ? { width: '100%', height: '100%' } : {};
|
||||
}, [loading, imgSize]);
|
||||
|
||||
const handleOnClick = useCallback(() => {
|
||||
onClick?.(props);
|
||||
}, [onClick, props]);
|
||||
|
||||
const handleResize = useCallback(
|
||||
(size: { width: number; height: number }) => {
|
||||
if (!autoSize) return;
|
||||
@@ -119,18 +131,47 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Progress
|
||||
percent={progress}
|
||||
type="dashboard"
|
||||
steps={{ count: 50, gap: 2 }}
|
||||
format={() => (
|
||||
<span className="font-size-20">{progress}%</span>
|
||||
)}
|
||||
trailColor="var(--ant-color-fill-secondary)"
|
||||
/>
|
||||
{progressType === 'dashboard' ? (
|
||||
<Progress
|
||||
percent={progress}
|
||||
type="dashboard"
|
||||
steps={{ count: 50, gap: 2 }}
|
||||
format={() => (
|
||||
<span className="font-size-20">{progress}%</span>
|
||||
)}
|
||||
trailColor="var(--ant-color-fill-secondary)"
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className="progress-wrapper"
|
||||
style={{ bottom: 'unset' }}
|
||||
>
|
||||
<Tooltip title={`${progress}%`} open={true}>
|
||||
<Progress
|
||||
style={{
|
||||
paddingInline: 0,
|
||||
borderRadius: 12,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.5)'
|
||||
}}
|
||||
percent={progress}
|
||||
percentPosition={{
|
||||
align: 'center',
|
||||
type: 'inner'
|
||||
}}
|
||||
type="line"
|
||||
size={[undefined, 6]}
|
||||
strokeLinecap="round"
|
||||
strokeColor="var(--color-white-1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
onClick={handleOnClick}
|
||||
className="img"
|
||||
style={{
|
||||
maxHeight: `min(${maxHeight}, 100%)`,
|
||||
@@ -138,12 +179,37 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
|
||||
}}
|
||||
>
|
||||
<AutoImage
|
||||
preview={preview}
|
||||
autoSize={autoSize}
|
||||
src={dataUrl}
|
||||
width={imgSize.width || 100}
|
||||
height={imgSize.height || 100}
|
||||
onLoad={handleOnLoad}
|
||||
/>
|
||||
{progress && progress < 100 && (
|
||||
<span className="progress-wrapper">
|
||||
<Tooltip title={`${progress}%`} open={true}>
|
||||
<Progress
|
||||
style={{
|
||||
paddingInline: 0,
|
||||
borderRadius: 12,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.5)'
|
||||
}}
|
||||
percent={progress}
|
||||
percentPosition={{
|
||||
align: 'center',
|
||||
type: 'inner'
|
||||
}}
|
||||
type="line"
|
||||
size={[undefined, 6]}
|
||||
strokeLinecap="round"
|
||||
strokeColor="var(--color-white-1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user