-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat/#35' into develop
- Loading branch information
Showing
16 changed files
with
553 additions
and
129 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Categories } from '@/constants/categories'; | ||
|
||
export const SelectCategory = ({ selectedCategory, setSelectedCategory }) => { | ||
const CategoryList = [...Categories]; | ||
const handleOnChange = (e) => { | ||
setSelectedCategory(e.target.id); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-3"> | ||
<div className="text-subTitle">Category</div> | ||
<div className="flex w-full gap-3"> | ||
{CategoryList.map((category) => ( | ||
<div className="box-border flex" key={category}> | ||
<input | ||
type="radio" | ||
name="category" | ||
id={category} | ||
className="hidden peer" | ||
onChange={handleOnChange} | ||
checked={selectedCategory === category} | ||
/> | ||
<label | ||
htmlFor={category} | ||
className="flex items-center px-3 py-[.375rem] border rounded-full cursor-pointer border-neutral-border-30 text-neutral-border-50 border-box peer-checked:border-primary-30 peer-checked:bg-primary-30 peer-checked:text-white" | ||
> | ||
{category} | ||
</label> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import Camera from '@/assets/imgs/camera.svg'; | ||
import ImgX from '@/assets/imgs/ImgX.svg?react'; | ||
import { useState } from 'react'; | ||
|
||
export const UploadPics = ({ onChange }) => { | ||
const [previewImages, setPreviewImages] = useState([]); | ||
const [files, setFiles] = useState([]); | ||
|
||
const getImageFiles = async (e) => { | ||
const newFiles = Array.from(e.target.files); | ||
|
||
if (newFiles.length + files.length > 10) { | ||
alert('이미지는 최대 10장까지 업로드가 가능합니다.'); | ||
return; | ||
} | ||
|
||
const validFiles = newFiles.filter((file) => file.type.match('image/.*')); | ||
if (validFiles.length !== newFiles.length) { | ||
alert('이미지 파일만 업로드가 가능합니다.'); | ||
} | ||
|
||
try { | ||
// Promise로 모든 미리보기 URL 생성 | ||
const newPreviews = await Promise.all( | ||
validFiles.map((file) => { | ||
// URL 생성 중 오류 가능성 대비 | ||
return new Promise((resolve, reject) => { | ||
try { | ||
resolve(URL.createObjectURL(file)); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
}); | ||
}), | ||
); | ||
|
||
// 모든 파일과 미리보기가 준비된 후 상태 업데이트 | ||
if (validFiles.length > 0 && newPreviews.length === validFiles.length) { | ||
const updatedFiles = [...files, ...validFiles]; | ||
const updatedPreviews = [...previewImages, ...newPreviews]; | ||
|
||
setFiles(updatedFiles); | ||
setPreviewImages(updatedPreviews); | ||
onChange(updatedFiles); // 부모 컴포넌트에 전달 | ||
} | ||
} catch (error) { | ||
alert('파일 처리 중 오류가 발생했습니다.'); | ||
return null; | ||
} | ||
}; | ||
|
||
const removeImage = (index) => { | ||
const urlToRevoke = previewImages[index]; | ||
|
||
const updatedFiles = files.filter((_, i) => i !== index); | ||
const updatedPreviews = previewImages.filter((_, i) => i !== index); | ||
|
||
setFiles(updatedFiles); | ||
setPreviewImages(updatedPreviews); | ||
onChange(updatedFiles); // 부모 컴포넌트에 전달 | ||
|
||
URL.revokeObjectURL(urlToRevoke); // URL 해제 | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-row items-end gap-2"> | ||
<label | ||
htmlFor="selectImages" | ||
className="flex flex-col flex-shrink-0 items-center justify-center w-20 h-20 bg-neutral-border-30 rounded-[.3125rem] mt-[.5625rem]" | ||
> | ||
<img src={Camera} alt="" className="w-[2.375rem] h-[2.375rem]" /> | ||
<span className="text-small text-neutral-border-50"> | ||
{files.length}/10 | ||
</span> | ||
</label> | ||
<input | ||
type="file" | ||
accept="image/*" | ||
id="selectImages" | ||
className="hidden" | ||
multiple | ||
onChange={getImageFiles} | ||
/> | ||
<div className="grid grid-flow-col gap-[.875rem] overflow-x-scroll scrollbar-hide pr-[.5625rem] pt-[.5625rem]"> | ||
{previewImages.map((src, index) => ( | ||
<div className="relative w-20 h-20" key={index}> | ||
<img | ||
src={src} | ||
alt={`Preview ${index + 1}`} | ||
className="object-cover w-20 h-20" | ||
/> | ||
<button | ||
onClick={() => removeImage(index)} | ||
className="absolute top-0 right-0 z-10 translate-x-1/2 -translate-y-1/2" | ||
> | ||
<ImgX className="w-[1.125rem] h-[1.125rem] text-neutral-border-50" /> | ||
</button> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { useNavigate } from 'react-router-dom'; | ||
import Pencil from '@/assets/imgs/pencil.svg' | ||
|
||
export const WriteButton = () => { | ||
const navigate = useNavigate(); | ||
return ( | ||
<button | ||
type="button" | ||
className="fixed flex items-center py-2 px-[1.875rem] bg-primary-base rounded-full text-white shadow-[.1875rem_.1875rem_.25rem_0rem_rgba(0,0,0,0.2)] cursor-pointer bottom-9 left-1/2 -translate-x-1/2 gap-[.375rem]" | ||
onClick={() => navigate('./write')} | ||
> | ||
<span>Write</span> | ||
<img src={Pencil} alt="" className='w-4 h-4'/> | ||
</button> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { TranslateButton } from '@/components/common/TranslateButton'; | ||
|
||
export const WriteContent = ({ | ||
content, | ||
setContent, | ||
translatedContent, | ||
setTranslatedContent, | ||
}) => { | ||
const handleOnChange = (e) => { | ||
setContent(e.target.value); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-[2.5rem]"> | ||
<div className="flex flex-col gap-3"> | ||
<label htmlFor="contentInput" className="text-subTitle"> | ||
Content | ||
</label> | ||
<div className="box-border flex flex-row w-full px-[.875rem] py-[1.125rem] border border-neutral-border-30 rounded-lg gap-[.625rem] items-start"> | ||
<textarea | ||
id="contentInput" | ||
rows={16} | ||
placeholder="Add a content." | ||
value={content} | ||
onChange={handleOnChange} | ||
className="w-full leading-none resize-none placeholder-neutral-border-50 scrollbar-hide" | ||
required | ||
/> | ||
<TranslateButton | ||
translateType="content" | ||
value={content} | ||
setValue={setTranslatedContent} | ||
/> | ||
</div> | ||
</div> | ||
{translatedContent && ( | ||
<div className="flex flex-col gap-3"> | ||
<label htmlFor="translatedContent" className="text-subTitle"> | ||
Translation of Content | ||
</label> | ||
<div className="box-border flex flex-row w-full px-[.875rem] py-[1.125rem] border border-neutral-border-30 rounded-lg gap-[.625rem] items-start"> | ||
<textarea | ||
id="translatedContent" | ||
rows={16} | ||
value={translatedContent} | ||
className="w-full leading-none bg-transparent resize-none placeholder-neutral-border-50 scrollbar-hide" | ||
disabled | ||
/> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { TranslateButton } from '@/components/common/TranslateButton'; | ||
|
||
export const WriteTitle = ({ title, setTitle }) => { | ||
const handleOnChange = (e) => { | ||
setTitle(e.target.value); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-3"> | ||
<label htmlFor="writeTitle" className="text-subTitle"> | ||
Title | ||
</label> | ||
<div className="box-border flex flex-row w-full px-[.875rem] py-[1.125rem] border border-neutral-border-30 rounded-lg gap-[.625rem]"> | ||
<input | ||
id="writeTitle" | ||
type="text" | ||
placeholder="Please add a title." | ||
value={title} | ||
onChange={handleOnChange} | ||
autoComplete="off" | ||
className="w-full leading-none placeholder-neutral-border-50" | ||
required | ||
/> | ||
<TranslateButton translateType="text" value={title} setValue={setTitle}/> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import TranslateImg from '@/assets/imgs/translate.svg'; | ||
|
||
/** 번역 컴포넌트 | ||
* @param {Object} props - 컴포넌트의 props | ||
* @param {'post' | 'content' | 'text'} props.translateType - 번역 타입 (게시된 post, 작성 중인 content, 단순 text) | ||
* @param {number | string} props.value - post 번역 시 number, 작성 중인 글 본문이나 단순 text 번역 시 string | ||
* @param {function} props.setValue - 해당 함수로 번역된 텍스트 전달 | ||
*/ | ||
export const TranslateButton = ({ translateType, value, setValue }) => { | ||
const translate = () => { | ||
if (value || value === 0) { | ||
if (translateType === 'post') { | ||
// postId 전달 시 게시글 번역 - value는 number | ||
console.log(value); | ||
} else if (translateType === 'content') { | ||
// 작성 중인 게시글 본문 번역 - value는 string | ||
// 모달 구현해야함 | ||
// 사용자가 선택한 언어 있으면 백에 알려주기 | ||
setValue(value); // 현재는 번역 안된 상태로 전달 | ||
} else if (translateType === 'text') { | ||
// 영어로 번역 - value는 string | ||
setValue(value); // 현재는 번역 안된 상태로 전달 | ||
} | ||
} | ||
}; | ||
|
||
return ( | ||
<button type="button" onClick={translate}> | ||
<img src={TranslateImg} alt="" className="w-[1.375rem] h-[1.375rem]" /> | ||
</button> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const Categories = ["Hospital", "University", "Restaurant"]; |
Oops, something went wrong.