Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Image Preview #954

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/icons/src/components/FileCsv.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const FileCsv = (props: SVGProps<SVGSVGElement>) => (
/>
<path
fill="#fff"
d="m8.943 13.687-.077.296c-.093.47-.337.895-.696 1.212-.358.25-.789.374-1.225.354-.778 0-1.352-.235-1.709-.698s-.516-1.138-.516-2.032.177-1.548.53-2.014c.351-.465.904-.738 1.658-.738.429-.023.854.084 1.22.307.321.236.542.583.62.974l.078.293h2.117l-.071-.455a3.47 3.47 0 0 0-1.244-2.262 4.13 4.13 0 0 0-2.696-.857c-1.46 0-2.593.497-3.363 1.471-.659.836-1.013 1.942-1.013 3.28 0 1.34.328 2.456.974 3.266.762.97 1.915 1.463 3.44 1.463a4 4 0 0 0 2.555-.857 4.1 4.1 0 0 0 1.452-2.532l.09-.471z"
d="m8.943 13.687-.077.296c-.093.47-.338.895-.696 1.212-.358.25-.789.374-1.225.354-.778 0-1.352-.235-1.709-.698s-.516-1.138-.516-2.032.177-1.548.53-2.014c.351-.465.904-.738 1.658-.738.428-.023.854.084 1.22.307.321.236.542.583.619.974l.08.293h2.116l-.072-.455a3.47 3.47 0 0 0-1.243-2.262 4.13 4.13 0 0 0-2.696-.857c-1.46 0-2.593.497-3.363 1.471-.659.836-1.013 1.942-1.013 3.28 0 1.34.328 2.456.973 3.266.762.97 1.916 1.463 3.44 1.463a4 4 0 0 0 2.556-.857 4.1 4.1 0 0 0 1.452-2.532l.09-.471z"
/>
</g>
<defs>
Expand Down
2 changes: 1 addition & 1 deletion packages/icons/src/components/GithubLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const GithubLogo = (props: SVGProps<SVGSVGElement>) => (
<g clipPath="url(#prefix__a)">
<path
fill="currentColor"
d="M22.39 6.42a12.1 12.1 0 0 0-4.367-4.477Q15.266.293 12 .293t-6.023 1.65A12.1 12.1 0 0 0 1.609 6.42Q0 9.248 0 12.594q0 4.02 2.289 7.232 2.289 3.21 5.914 4.444.422.08.625-.112a.63.63 0 0 0 .203-.48l-.008-.865q-.008-.712-.008-1.425l-.36.063q-.342.065-.866.056a6.4 6.4 0 0 1-1.086-.112 2.4 2.4 0 0 1-1.047-.48 2.03 2.03 0 0 1-.688-.985l-.156-.368a4 4 0 0 0-.492-.817q-.336-.45-.68-.609l-.109-.08a1.2 1.2 0 0 1-.203-.192.9.9 0 0 1-.14-.224q-.048-.113.078-.185.124-.072.453-.071l.312.047q.312.064.773.385.462.32.758.832.36.657.867 1.002.508.345 1.024.344.515 0 .89-.08.375-.081.703-.24.141-1.074.766-1.65a10.5 10.5 0 0 1-1.602-.289 6.3 6.3 0 0 1-1.468-.625 4.2 4.2 0 0 1-1.258-1.073q-.5-.64-.82-1.681-.32-1.042-.32-2.403 0-1.938 1.234-3.3-.58-1.456.11-3.267.453-.144 1.343.217.891.36 1.305.616.414.255.664.433a10.8 10.8 0 0 1 3-.417q1.546 0 3 .417l.594-.385a8.3 8.3 0 0 1 1.437-.704q.828-.321 1.266-.176.703 1.809.125 3.267 1.234 1.36 1.234 3.3 0 1.36-.32 2.41t-.828 1.681q-.507.633-1.266 1.065a6.3 6.3 0 0 1-1.469.625q-.71.193-1.6.289.81.72.811 2.274v3.38q0 .286.196.48.195.191.617.111 3.625-1.232 5.914-4.444Q24 16.615 24 12.594q0-3.347-1.61-6.174"
d="M22.39 6.42a12.1 12.1 0 0 0-4.367-4.477Q15.266.293 12 .293t-6.023 1.65A12.1 12.1 0 0 0 1.609 6.42Q0 9.247 0 12.594q0 4.02 2.289 7.232 2.289 3.21 5.914 4.444.422.08.625-.112a.63.63 0 0 0 .203-.48l-.008-.865q-.008-.712-.008-1.425l-.36.063q-.342.065-.866.056a6.5 6.5 0 0 1-1.086-.112 2.4 2.4 0 0 1-1.047-.48 2.03 2.03 0 0 1-.688-.985l-.156-.368a4 4 0 0 0-.492-.817q-.336-.45-.68-.609l-.109-.08a1.2 1.2 0 0 1-.203-.192.9.9 0 0 1-.14-.224q-.048-.113.078-.185.124-.072.453-.072l.312.048q.312.063.773.385.462.32.758.832.36.657.867 1.001.508.345 1.024.345.515 0 .89-.08.375-.081.703-.24.141-1.074.766-1.65a10.5 10.5 0 0 1-1.602-.289 6.3 6.3 0 0 1-1.468-.625 4.2 4.2 0 0 1-1.258-1.073q-.5-.64-.82-1.681-.32-1.042-.32-2.403 0-1.938 1.234-3.3-.58-1.457.11-3.267.453-.144 1.343.217.891.36 1.305.616T9 6.652a10.8 10.8 0 0 1 3-.417q1.546 0 3 .417l.594-.385a8.3 8.3 0 0 1 1.437-.704q.828-.321 1.266-.176.703 1.809.125 3.267 1.234 1.36 1.234 3.3 0 1.36-.32 2.41t-.828 1.681q-.507.633-1.266 1.065a6.3 6.3 0 0 1-1.469.625q-.71.193-1.6.289.81.72.811 2.274v3.38q0 .286.196.48.195.191.617.111 3.625-1.232 5.914-4.444Q24 16.615 24 12.594q0-3.347-1.61-6.174"
/>
</g>
<defs>
Expand Down
2 changes: 1 addition & 1 deletion packages/icons/src/components/HttpRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const HttpRequest = (props: SVGProps<SVGSVGElement>) => (
/>
<path
fill="#F472B6"
d="M5.915 10.01a.33.33 0 0 1 .204.152l.995 1.666c.074.124.074.22 0 .343l-.995 1.667a.332.332 0 1 1-.569-.343l.665-1.112a.4.4 0 0 1-.115.017H4.4a.4.4 0 1 1 0-.8h1.7a.4.4 0 0 1 .116.017l-.22-.365-.446-.747a.334.334 0 0 1 .365-.495M14.948 14.81h-.93c-.466 2.048-1.304 3.258-2.048 3.258-.745 0-1.583-1.21-2.048-3.258H8.99c.186 1.21.558 2.234 1.117 2.979-1.582-.559-2.793-1.583-3.537-2.979H5.547c1.117 2.42 3.537 4.189 6.423 4.189 2.885 0 5.306-1.769 6.423-4.189h-1.024c-.745 1.396-1.955 2.42-3.538 2.979.466-.745.838-1.769 1.117-2.979m-4.84-8.6c-.56.745-.93 1.769-1.117 2.979h.93c.466-2.048 1.304-3.258 2.049-3.258s1.582 1.21 2.048 3.258h.93c-.186-1.21-.558-2.234-1.117-2.979 1.583.559 2.793 1.583 3.538 2.979h1.024C17.276 6.769 14.855 5 11.97 5S6.664 6.769 5.547 9.189H6.57c.744-1.396 1.955-2.42 3.537-2.979M10.167 11.567H9.1V10.9c0-.219-.18-.4-.4-.4-.219 0-.4.181-.4.4v2.4c0 .219.181.4.4.4s.4-.181.4-.4v-.933h1.067v.933c0 .219.181.4.4.4.218 0 .4-.181.4-.4v-2.4c0-.219-.182-.4-.4-.4s-.4.181-.4.4zM11.7 11.3h.502v2c0 .219.181.4.4.4s.4-.181.4-.4v-2h.498c.219 0 .4-.181.4-.4s-.181-.4-.4-.4h-1.8c-.219 0-.4.181-.4.4s.283.4.502.4zm3 0h.502v2c0 .219.181.4.4.4s.4-.181.4-.4v-2h.498c.219 0 .4-.181.4-.4s-.181-.4-.4-.4h-1.8c-.219 0-.4.181-.4.4s.283.4.502.4zm4.467-.8h-1.334a.535.535 0 0 0-.533.533V13.3c0 .219.181.4.4.4s.4-.181.4-.4v-.667h1.067c.442 0 .8-.362.8-.8V11.3c0-.437-.358-.8-.8-.8m-.001 1.333h-1.067V11.3h1.067z"
d="M5.915 10.01a.33.33 0 0 1 .204.152l.995 1.666c.074.124.074.22 0 .343l-.995 1.667a.332.332 0 1 1-.569-.343l.665-1.112a.4.4 0 0 1-.115.017H4.4a.4.4 0 1 1 0-.8h1.7a.4.4 0 0 1 .116.017l-.22-.365-.446-.747a.334.334 0 0 1 .365-.495M14.948 14.81h-.93c-.466 2.048-1.304 3.258-2.048 3.258-.745 0-1.583-1.21-2.048-3.258H8.99c.186 1.21.558 2.234 1.117 2.979-1.582-.559-2.793-1.583-3.537-2.979H5.547c1.117 2.42 3.537 4.189 6.423 4.189 2.885 0 5.306-1.769 6.423-4.189h-1.024c-.745 1.396-1.955 2.42-3.538 2.979.466-.745.838-1.769 1.117-2.979m-4.84-8.6c-.559.745-.93 1.769-1.117 2.979h.93c.466-2.048 1.304-3.258 2.049-3.258s1.582 1.21 2.048 3.258h.93c-.186-1.21-.558-2.234-1.117-2.979 1.583.559 2.793 1.583 3.538 2.979h1.024C17.276 6.769 14.855 5 11.97 5S6.664 6.769 5.547 9.189H6.57c.744-1.396 1.955-2.42 3.537-2.979zM10.167 11.567H9.1V10.9c0-.219-.18-.4-.4-.4-.219 0-.4.181-.4.4v2.4c0 .219.181.4.4.4s.4-.181.4-.4v-.933h1.067v.933c0 .219.181.4.4.4.218 0 .4-.181.4-.4v-2.4c0-.219-.182-.4-.4-.4s-.4.181-.4.4zM11.7 11.3h.502v2c0 .219.181.4.4.4s.4-.181.4-.4v-2h.498c.219 0 .4-.181.4-.4s-.181-.4-.4-.4h-1.8c-.219 0-.4.181-.4.4s.283.4.502.4zm3 0h.502v2c0 .219.181.4.4.4s.4-.181.4-.4v-2h.498c.219 0 .4-.181.4-.4s-.181-.4-.4-.4h-1.8c-.219 0-.4.181-.4.4s.283.4.502.4zm4.467-.8h-1.334a.535.535 0 0 0-.533.533V13.3c0 .219.181.4.4.4s.4-.181.4-.4v-.667h1.067c.442 0 .8-.362.8-.8V11.3c0-.437-.358-.8-.8-.8m-.001 1.333h-1.067V11.3h1.067z"
/>
</svg>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/icons/src/components/Phone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const Phone = (props: SVGProps<SVGSVGElement>) => (
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.338 1.85.573 2.81.7A2 2 0 0 1 22 16.92"
d="M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.362 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.338 1.85.573 2.81.7A2 2 0 0 1 22 16.92"
/>
</svg>
);
Expand Down
28 changes: 28 additions & 0 deletions packages/icons/src/components/RotateCw.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react';
import type { SVGProps } from 'react';
const RotateCw = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 2v6h-6"
/>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 13a9 9 0 1 1-3-7.7L21 8"
/>
</svg>
);
export default RotateCw;
21 changes: 21 additions & 0 deletions packages/icons/src/components/ZoomIn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import type { SVGProps } from 'react';
const ZoomIn = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16M21 21l-4.35-4.35M11 8v6M8 11h6"
/>
</svg>
);
export default ZoomIn;
21 changes: 21 additions & 0 deletions packages/icons/src/components/ZoomOut.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import type { SVGProps } from 'react';
const ZoomOut = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
fill="none"
viewBox="0 0 24 24"
{...props}
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16M21 21l-4.35-4.35M8 11h6"
/>
</svg>
);
export default ZoomOut;
3 changes: 3 additions & 0 deletions packages/icons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export { default as PlusCircle } from './components/PlusCircle';
export { default as Qrcode } from './components/Qrcode';
export { default as Redo2 } from './components/Redo2';
export { default as RefreshCcw } from './components/RefreshCcw';
export { default as RotateCw } from './components/RotateCw';
export { default as Search } from './components/Search';
export { default as SendMail } from './components/SendMail';
export { default as Settings } from './components/Settings';
Expand Down Expand Up @@ -137,3 +138,5 @@ export { default as Users } from './components/Users';
export { default as Webhook } from './components/Webhook';
export { default as X } from './components/X';
export { default as Zap } from './components/Zap';
export { default as ZoomIn } from './components/ZoomIn';
export { default as ZoomOut } from './components/ZoomOut';
126 changes: 124 additions & 2 deletions packages/ui-lib/src/base/file/preview/image/ImagePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,130 @@
import { RotateCw, ZoomIn, ZoomOut, RefreshCcw } from '@teable/icons';
import { useEffect, useState } from 'react';
import type { IFileItemInner } from '../FilePreviewContext';

interface IImagePreviewProps extends IFileItemInner {}

export const ImagePreview = (props: IImagePreviewProps) => {
const { src, name } = props;
return <img className="max-h-full max-w-full" src={src} alt={name} />;
const [scale, setScale] = useState(1);
const [rotate, setRotate] = useState(0);

const [position, setPosition] = useState({
oldX: 0,
oldY: 0,
x: 0,
y: 0,
});
const [isPanning, setPanning] = useState(false);

const handleZoomIn = () => {
setPosition({
...position,
x: (position.x -= 135.5),
y: (position.y -= 65.6),
});
setScale(scale + 0.65);
};

const handleZoomOut = () => {
if (scale <= 0.35) return;
setScale(scale - 0.65);
};
const handleReset = () => {
setScale(1);
setRotate(0);
setPosition({
oldX: 0,
oldY: 0,
x: 0,
y: 0,
});
};
const handleRotate = () => {
setRotate(rotate + 30);
};

const onMouseDown = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.preventDefault();
if (scale > 1) {
setPanning(true);
setPosition({
...position,
oldX: e.clientX,
oldY: e.clientY,
});
}
};

useEffect(() => {
const mouseup = () => {
setPanning(false);
};

const mousemove = (event: MouseEvent) => {
if (isPanning) {
if (position.x == 0) {
return;
}
setPosition({
...position,
x: position.x + event.clientX - position.oldX,
y: position.y + event.clientY - position.oldY,
oldX: event.clientX,
oldY: event.clientY,
});
}
};

window.addEventListener('mouseup', mouseup);
window.addEventListener('mousemove', mousemove);

return () => {
window.removeEventListener('mouseup', mouseup);
window.removeEventListener('mousemove', mousemove);
};
});

return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div
className="flex-col flex h-full justify-center items-center overflow-hidden"
style={{
cursor: `${scale > 1 ? 'grabbing' : 'auto'}`,
}}
onMouseDown={(e) => onMouseDown(e)}
>
<div
className="img-box"
style={{ transform: `translate(${position.x}px,${position.y}px) scale(${scale})` }}
>
<img
className="max-h-2xl max-w-2xl items-center"
src={src}
alt={name}
style={{
transform: `rotate(${rotate}deg)`,
}}
draggable={false}
/>
</div>
<div className=" absolute bottom-0 right-30 justify-center">
{/* zoomin */}
<button className=" p-2 rounded-md hover:bg-black/40" onClick={handleZoomIn}>
<ZoomIn className="text-xl" />
</button>
{/* zoomout */}
<button className=" p-2 rounded-md hover:bg-black/40" onClick={handleZoomOut}>
<ZoomOut className="text-xl" />
</button>
{/* rotate */}
<button className=" p-2 rounded-md hover:bg-black/40" onClick={handleRotate}>
<RotateCw className="text-xl" />
</button>
{/* reset */}
<button className="p-2 rounded-md hover:bg-black/40" onClick={handleReset}>
<RefreshCcw className="text-xl" />
</button>
</div>
</div>
);
};