Merge branch 'fe/feat/265-image-upload-windowing' into 'fe/develop'
Feat: 이미지 업로드 form에 windowing 적용 - S11P21S002-265 See merge request s11-s-project/S11P21S002!265
This commit is contained in:
commit
48da0d856a
45
frontend/package-lock.json
generated
45
frontend/package-lock.json
generated
@ -22,6 +22,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@tanstack/react-query": "^5.52.1",
|
"@tanstack/react-query": "^5.52.1",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
"axios": "^1.7.5",
|
"axios": "^1.7.5",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@ -35,6 +36,8 @@
|
|||||||
"react-resizable-panels": "^2.1.1",
|
"react-resizable-panels": "^2.1.1",
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-slick": "^0.30.2",
|
"react-slick": "^0.30.2",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
|
"react-window": "^1.8.10",
|
||||||
"recharts": "^2.12.7",
|
"recharts": "^2.12.7",
|
||||||
"slick-carousel": "^1.8.1",
|
"slick-carousel": "^1.8.1",
|
||||||
"sweetalert2": "^11.14.1",
|
"sweetalert2": "^11.14.1",
|
||||||
@ -6950,6 +6953,15 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-window": {
|
||||||
|
"version": "1.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz",
|
||||||
|
"integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.6",
|
"version": "1.20.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
|
||||||
@ -11032,6 +11044,12 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/memoize-one": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/memoizerific": {
|
"node_modules/memoizerific": {
|
||||||
"version": "1.11.3",
|
"version": "1.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz",
|
||||||
@ -12696,6 +12714,33 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-virtualized-auto-sizer": {
|
||||||
|
"version": "1.0.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz",
|
||||||
|
"integrity": "sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-window": {
|
||||||
|
"version": "1.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz",
|
||||||
|
"integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@tanstack/react-query": "^5.52.1",
|
"@tanstack/react-query": "^5.52.1",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
"axios": "^1.7.5",
|
"axios": "^1.7.5",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@ -41,6 +42,8 @@
|
|||||||
"react-resizable-panels": "^2.1.1",
|
"react-resizable-panels": "^2.1.1",
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-slick": "^0.30.2",
|
"react-slick": "^0.30.2",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
|
"react-window": "^1.8.10",
|
||||||
"recharts": "^2.12.7",
|
"recharts": "^2.12.7",
|
||||||
"slick-carousel": "^1.8.1",
|
"slick-carousel": "^1.8.1",
|
||||||
"sweetalert2": "^11.14.1",
|
"sweetalert2": "^11.14.1",
|
||||||
|
@ -4,6 +4,7 @@ import { cn } from '@/lib/utils';
|
|||||||
import useAuthStore from '@/stores/useAuthStore';
|
import useAuthStore from '@/stores/useAuthStore';
|
||||||
import { CircleCheckBig, CircleDashed, CircleX, X } from 'lucide-react';
|
import { CircleCheckBig, CircleDashed, CircleX, X } from 'lucide-react';
|
||||||
import useUploadImageFileQuery from '@/queries/projects/useUploadImageFileQuery';
|
import useUploadImageFileQuery from '@/queries/projects/useUploadImageFileQuery';
|
||||||
|
import { FixedSizeList } from 'react-window';
|
||||||
|
|
||||||
export default function ImageUploadFileForm({
|
export default function ImageUploadFileForm({
|
||||||
onClose,
|
onClose,
|
||||||
@ -135,48 +136,56 @@ export default function ImageUploadFileForm({
|
|||||||
)}
|
)}
|
||||||
{files.length > 0 && (
|
{files.length > 0 && (
|
||||||
<ul className="m-0 max-h-[260px] list-none overflow-y-auto p-0">
|
<ul className="m-0 max-h-[260px] list-none overflow-y-auto p-0">
|
||||||
{files.map((file, index) => (
|
<FixedSizeList
|
||||||
<li
|
height={260}
|
||||||
key={index}
|
itemCount={files.length}
|
||||||
className="flex items-center justify-between p-1"
|
itemSize={40}
|
||||||
>
|
width="100%"
|
||||||
<span className="truncate">{file.webkitRelativePath || file.name}</span>
|
>
|
||||||
{isUploading ? (
|
{({ index, style }) => (
|
||||||
<div className="p-2">
|
<li
|
||||||
{isUploaded ? (
|
key={index}
|
||||||
<CircleCheckBig
|
className="flex items-center justify-between p-1"
|
||||||
className="stroke-green-500"
|
style={style}
|
||||||
|
>
|
||||||
|
<span className="truncate">{files[index].webkitRelativePath || files[index].name}</span>
|
||||||
|
{isUploading ? (
|
||||||
|
<div className="p-2">
|
||||||
|
{isUploaded ? (
|
||||||
|
<CircleCheckBig
|
||||||
|
className="stroke-green-500"
|
||||||
|
size={16}
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
|
) : isFailed ? (
|
||||||
|
<CircleX
|
||||||
|
className="stroke-red-500"
|
||||||
|
size={16}
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CircleDashed
|
||||||
|
className="stroke-gray-500"
|
||||||
|
size={16}
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className={'cursor-pointer p-2'}
|
||||||
|
onClick={() => handleRemoveFile(index)}
|
||||||
|
>
|
||||||
|
<X
|
||||||
|
color="red"
|
||||||
size={16}
|
size={16}
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
/>
|
/>
|
||||||
) : isFailed ? (
|
</button>
|
||||||
<CircleX
|
)}
|
||||||
className="stroke-red-500"
|
</li>
|
||||||
size={16}
|
)}
|
||||||
strokeWidth="2"
|
</FixedSizeList>
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<CircleDashed
|
|
||||||
className="stroke-gray-500"
|
|
||||||
size={16}
|
|
||||||
strokeWidth="2"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
className={'cursor-pointer p-2'}
|
|
||||||
onClick={() => handleRemoveFile(index)}
|
|
||||||
>
|
|
||||||
<X
|
|
||||||
color="red"
|
|
||||||
size={16}
|
|
||||||
strokeWidth="2"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
{isUploading ? (
|
{isUploading ? (
|
||||||
|
@ -56,7 +56,6 @@ export default function ProjectDirectoryItem({
|
|||||||
key={`${projectId}-${item.imageTitle}`}
|
key={`${projectId}-${item.imageTitle}`}
|
||||||
item={item}
|
item={item}
|
||||||
depth={depth + 1}
|
depth={depth + 1}
|
||||||
folderId={folderData.id}
|
|
||||||
selected={image?.id === item.id}
|
selected={image?.id === item.id}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -2,12 +2,10 @@ import { cn } from '@/lib/utils';
|
|||||||
import { ImageResponse } from '@/types';
|
import { ImageResponse } from '@/types';
|
||||||
import { ArrowDownToLine, Check, CircleSlash, Image, Loader, Minus, Send } from 'lucide-react';
|
import { ArrowDownToLine, Check, CircleSlash, Image, Loader, Minus, Send } from 'lucide-react';
|
||||||
import useCanvasStore from '@/stores/useCanvasStore';
|
import useCanvasStore from '@/stores/useCanvasStore';
|
||||||
import useProjectStore from '@/stores/useProjectStore';
|
|
||||||
|
|
||||||
export default function ProjectFileItem({
|
export default function ProjectFileItem({
|
||||||
className = '',
|
className = '',
|
||||||
item,
|
item,
|
||||||
folderId = 0,
|
|
||||||
depth = 0,
|
depth = 0,
|
||||||
selected,
|
selected,
|
||||||
}: {
|
}: {
|
||||||
@ -19,11 +17,9 @@ export default function ProjectFileItem({
|
|||||||
}) {
|
}) {
|
||||||
const paddingLeft = depth * 12;
|
const paddingLeft = depth * 12;
|
||||||
const setImage = useCanvasStore((state) => state.setImage);
|
const setImage = useCanvasStore((state) => state.setImage);
|
||||||
const setFolderId = useProjectStore((state) => state.setFolderId);
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
setImage(item);
|
setImage(item);
|
||||||
setFolderId(folderId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user