Skip to content

Commit

Permalink
[Feature] - 여행기 등록 페이지에 필요한 공통 컴포넌트 구현(리버) (#89)
Browse files Browse the repository at this point in the history
* feat: MultiImageUpload 컴포넌트 구현

* feat: ThumbnailUpload 컴포넌트 구현

* fix: emotion css를 styled로 수정

- storybook에서 emotion css가 적용되지 않는 문제가 있어서 emotion styled로 수정

* test: ThumnailUpload 컴포넌트 storybook 추가

* feat: MultiImageUpload 컴포넌트 이미지 삭제 기능 구현

* refactor: MultiImageUpload 컴포넌트에서 함수명 코드 컨벤션에 맞게 수정

* feat: ThumbnailUpload 컴포넌트 썸네일 수정 기능 구현

* feat: ThumbnailUploadButton에 gap 수정

* refactor: ThumbnailUpload 컴포넌트에서 중복 제거

* refactor: ThumbnailUpload 컴포넌트에서 화살표 함수로 단순화

* fix: MulitiImageUpload 컴포넌트에서 emotion css를 emotion styled로 수정

- storybook에서 emotion css 적용 되지 않는 이슈때문에 수정

* refactor: 이미지 업로드 로직을 useImageUpload로 분리

* test: MultiImageUpload 컴포넌트 storybook 추가

* fix: ThumbnailUpload 컴포넌트 storybook title 수정

* fix: MultiImageUpload 컴포넌트 storybook title 수정

* refactor: ThumbnailUpload 컴포넌트 storybook에서 base64를 mageUrl로 수정

-CORS 정책때문에 외부 URL에서 이미지를 직접 가져오는 것이 안됐었다.
- 이 때문에 imageUrl 대신 base64를 사용했었다
- base64 값이 너무 길다
- 때문에 무료 CORS 프록시 서비를 사용하여 imageUrl을 사용하는 방법으로 수정

* feat: MultiImageUpload 컴포넌트의 이미지 렌더링 부분에 스크롤 추가

* test: MultiImageUpload 컴포넌트 storybook에 이미지 많이 첨부한 경우 추가

* refactor: MultiImageUpload 컴포넌트 삭제 버튼에 svg 사용

* refactor: MultiImageUpload 컴포넌트에서 styled 컴포넌트명 수정

* feat: useDragScroll hook 구현

* feat: MultiImageUpload 컴포넌트에 드래그 스크롤 기능 추가

* feat: MultiImageUpload 컴포넌트에 y축 스크롤 hidden 추가

* refactor: MultiImageUpload 컴포넌트에서 사진 추가 버튼 UI 수정

---------

Co-authored-by: jinyoung <[email protected]>
  • Loading branch information
0jenn0 and jinyoung234 authored Jul 23, 2024
1 parent 64a8dd3 commit 51f1960
Show file tree
Hide file tree
Showing 12 changed files with 649 additions and 0 deletions.
11 changes: 11 additions & 0 deletions frontend/src/assets/svg/camera-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions frontend/src/assets/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export { default as DownArrow } from "./down-arrow.svg";
export { default as Marker } from "./marker.svg";
export { default as markerUrl } from "./marker.svg?url";
export { default as EmptyHeart } from "./empty-heart.svg";
export { default as PictureIcon } from "./picture-icon.svg";
export { default as XIcon } from "./x-icon.svg";
export { default as Tturi } from "./tturi.svg";
export { default as RecycleBin } from "./recycle-bin.svg";
export { default as ChevronsRight } from "./chevrons-right.svg";
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/assets/svg/picture-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/svg/x-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from "react";

import type { Meta, StoryObj } from "@storybook/react";

import MultiImageUpload from "./MultiImageUpload";

const meta = {
title: "common/MultiImageUpload",
component: MultiImageUpload,
decorators: [
(Story, context) => {
return (
<div style={{ width: "48rem" }}>
<Story args={{ ...context.args }} />
</div>
);
},
],
} satisfies Meta<typeof MultiImageUpload>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};

export const WithImages: Story = {
decorators: [
(Story) => {
React.useEffect(() => {
const fetchAndCreateFile = async () => {
const imageUrl =
"https://api.allorigins.win/raw?url=https://i.pinimg.com/474x/df/6d/1a/df6d1a665685af3c0eb7e4c6a0c40169.jpg";
const file = new File([await fetch(imageUrl).then((r) => r.blob())], "example.png", {
type: "image/png",
});

const files = Array(3).fill(file);

const dataTransfer = new DataTransfer();

files.map((file) => dataTransfer.items.add(file));

const inputElement = document.querySelector('input[type="file"]') as HTMLInputElement;
if (inputElement) {
Object.defineProperty(inputElement, "files", {
value: dataTransfer.files,
});

const event = new Event("change", { bubbles: true });
inputElement.dispatchEvent(event);
}
};

fetchAndCreateFile();
}, []);

return <Story />;
},
],
};

export const WithManyImages: Story = {
decorators: [
(Story) => {
React.useEffect(() => {
const fetchAndCreateFile = async () => {
const imageUrl =
"https://api.allorigins.win/raw?url=https://i.pinimg.com/474x/df/6d/1a/df6d1a665685af3c0eb7e4c6a0c40169.jpg";
const file = new File([await fetch(imageUrl).then((r) => r.blob())], "example.png", {
type: "image/png",
});

const files = Array(7).fill(file);

const dataTransfer = new DataTransfer();

files.map((file) => dataTransfer.items.add(file));

const inputElement = document.querySelector('input[type="file"]') as HTMLInputElement;
if (inputElement) {
Object.defineProperty(inputElement, "files", {
value: dataTransfer.files,
});

const event = new Event("change", { bubbles: true });
inputElement.dispatchEvent(event);
}
};

fetchAndCreateFile();
}, []);

return <Story />;
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import styled from "@emotion/styled";

export const MultiImageUploadContainer = styled.div`
display: flex;
width: 100%;
justify-content: flex-start;
align-items: center;
gap: ${(props) => props.theme.spacing.m};
`;

export const MultiImageUploadButton = styled.button`
display: flex;
width: 100%;
padding: ${(props) => props.theme.spacing.s};
border: 1px solid ${(props) => props.theme.colors.border};
justify-content: center;
align-items: center;
gap: ${(props) => props.theme.spacing.xs};
${(props) => props.theme.typography.mobile.detailBold};
color: ${(props) => props.theme.colors.text.secondary};
border-radius: 0.4rem;
`;

export const MultiImageUploadPictureContainer = styled.div`
display: flex;
align-items: center;
flex: 1;
width: 100%;
overflow-x: auto-scroll;
justify-content: flex-start;
gap: ${(props) => props.theme.spacing.m};
`;

export const MultiImageUploadPictureWrapper = styled.div`
display: flex;
position: relative;
justify-content: flex-start;
gap: ${(props) => props.theme.spacing.m};
`;

export const MultiImageUploadPicture = styled.img`
width: 6rem;
height: 6rem;
object-fit: cover;
object-position: center;
border-radius: 0.4rem;
`;

export const MultiImageUploadPicturesInfo = styled.div`
display: flex;
width: 6rem;
height: 6rem;
border-radius: 0.4rem;
justify-content: center;
align-items: center;
border: 1px solid ${(props) => props.theme.colors.border};
flex-direction: column;
gap: ${(props) => props.theme.spacing.s};
p {
${(props) => props.theme.typography.mobile.detailBold}
color: ${(props) => props.theme.colors.text.secondary}
}
`;

export const MultiImageUploadPictureAddButton = styled.button<{ $hasPicture: boolean }>`
display: flex;
width: 6rem;
height: 6rem;
margin-top: ${({ $hasPicture }) => ($hasPicture ? "0" : "0.5rem")};
border-radius: 0.4rem;
justify-content: center;
align-items: center;
border: 1px solid ${(props) => props.theme.colors.border};
flex-direction: column;
gap: ${(props) => props.theme.spacing.s};
p {
${(props) => props.theme.typography.mobile.detailBold}
color: ${(props) => props.theme.colors.text.secondary}
}
svg {
width: 2rem;
}
`;

export const MultiImageUploadDeleteButton = styled.button`
display: flex;
position: absolute;
top: -1rem;
right: -1rem;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
border: 1px solid ${(props) => props.theme.colors.border};
background-color: #fff;
border-radius: 50%;
svg {
width: 0.8rem;
}
`;

export const MultiImageUploadHiddenInput = styled.input`
display: none;
`;

export const ImageScrollContainer = styled.div<{ $isDragging: boolean }>`
display: flex;
overflow: auto hidden;
width: 100%;
height: 7rem;
padding: 1rem 1rem 0 0;
padding-bottom: ${(props) => props.theme.spacing.s};
flex: 1;
justify-content: flex-start;
align-items: center;
gap: ${(props) => props.theme.spacing.m};
scrollbar-width: none;
cursor: ${({ $isDragging }) => ($isDragging ? "grab" : "pointer")};
`;

export const MultiImageUploadSVGWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 2.5rem;
height: 2.5rem;
svg {
width: 2rem;
}
`;
Loading

0 comments on commit 51f1960

Please sign in to comment.