Skip to content

Commit

Permalink
Merge pull request #5 from codeit-bootcamp-frontend/React-강수민
Browse files Browse the repository at this point in the history
React 강수민
  • Loading branch information
hpk5802 authored Oct 16, 2024
2 parents dacc632 + f74cc9d commit 75679ae
Show file tree
Hide file tree
Showing 32 changed files with 994 additions and 126 deletions.
213 changes: 213 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="판다 마켓" />
<meta property="og:description" content="일상의 모든 물건을 거래해보세요" />
<meta property="og:url" content="https://ksm-codeit-sprint.netlify.app/" />
<meta property="og:image" content="assets/images/home/logo.png" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="판다 마켓" />
<link rel="stylesheet" href="/style/style.css" />
<title>판다마켓</title>
</head>
<body>
<header>
<h1 class="logo">
<a href="/" class="link-home" title="판다마켓 홈 이동">
<img
src="assets/images/home/logo.png"
class="logo-img logo-pc"
alt="판다마켓 로고"
/>
<img
src="assets/images/home/logo_mobile.png"
class="logo-img logo-mobile"
alt="판다마켓 로고"
/>
</a>
</h1>
<a href="pages/login.html" class="link-login" title="로그인 페이지 이동">
로그인
</a>
</header>
<main>
<section class="section-layout section-layout-bg top">
<div class="section-wrap">
<div class="section-content">
<div class="section-content-inner">
<h2 class="section-title">
일상의 모든 물건을<br />
거래해 보세요
</h2>
<a
href="pages/items.html"
class="link-item"
title="아이템 페이지 이동"
>구경하러 가기</a
>
</div>
<img
src="assets/images/home/img_home_top.png"
class="img-home top"
alt="일상의 모든 물건을 거래해 보세요"
/>
</div>
</div>
</section>
<section class="section-layout section-layout-card">
<div class="section-wrap">
<div class="section-content">
<img
class="img-pc"
src="assets/images/home/img_home_01.png"
alt="Hot item 이미지"
/>
<img
class="img-tablet"
src="assets/images/home/img_home_01_tablet.png"
alt="Hot item 이미지"
/>
<img
class="img-mobile"
src="assets/images/home/img_home_01_mobile.png"
alt="Hot item 이미지"
/>
<div class="section-content-inner">
<div>
<span class="badge">Hot item</span>
<h2 class="section-title">
인기 상품을<br />
확인해 보세요
</h2>
<p class="section-desc">
가장 HOT한 중고거래 물품을<br />
판다 마켓에서 확인해 보세요
</p>
</div>
</div>
</div>
</div>
</section>
<section class="section-layout section-layout-card">
<div class="section-wrap">
<div class="section-content">
<div class="section-content-inner">
<div>
<span class="badge">Search</span>
<h2 class="section-title">
구매를 원하는<br />
상품을 검색하세요
</h2>
<p class="section-desc">
구매하고 싶은 물품은 검색해서<br />
쉽게 찾아보세요
</p>
</div>
</div>
<img
class="img-pc"
src="assets/images/home/img_home_02.png"
alt="Search 이미지"
/>
<img
class="img-tablet"
src="assets/images/home/img_home_02_tablet.png"
alt="Search 이미지"
/>
<img
class="img-mobile"
src="assets/images/home/img_home_02_mobile.png"
alt="Search 이미지"
/>
</div>
</div>
</section>
<section class="section-layout section-layout-card">
<div class="section-wrap">
<div class="section-content">
<img
class="img-pc"
src="assets/images/home/img_home_03.png"
alt="Register 이미지"
/>
<img
class="img-tablet"
src="assets/images/home/img_home_03_tablet.png"
alt="Register 이미지"
/>
<img
class="img-mobile"
src="assets/images/home/img_home_03_mobile.png"
alt="Register 이미지"
/>
<div class="section-content-inner">
<div>
<span class="badge">Register</span>
<h2 class="section-title">
판매를 원하는<br />
상품을 등록하세요
</h2>
<p class="section-desc">
어떤 물건이든 판매하고 싶은 상품을<br />
쉽게 등록하세요
</p>
</div>
</div>
</div>
</div>
</section>
<section class="section-layout section-layout-bg bottom">
<div class="section-wrap">
<div class="section-content">
<div class="section-content-inner">
<h2 class="section-title mb-60">
믿을 수 있는<br />
판다마켓 중고 거래
</h2>
</div>
<img
src="assets/images/home/img_home_bottom.png"
class="img-home bottom"
alt="믿을 수 있는 판다마켓 중고 거래"
/>
</div>
</div>
</section>
</main>
<footer>
<div class="footer-wrap">
<div class="corp">©codeit - 2024</div>
<div class="links">
<a href="pages/privacy.html" title="Privacy Policy 페이지 이동"
>Privacy Policy</a
>
<a href="pages/faq.html" title="FAQ 페이지 이동">FAQ</a>
</div>
<div class="sns">
<a
href="https://www.facebook.com"
target="_blank"
title="페이스북 바로가기"
>
<img src="assets/images/icons/ic_facebook.png" alt="페이스북" />
</a>
<a href="https://x.com" target="_blank" title="트위터 이동">
<img src="assets/images/icons/ic_twitter.png" alt="트위터" />
</a>
<a href="https://www.youtube.com" target="_blank" title="유튜브 이동">
<img src="assets/images/icons/ic_youtube.png" alt="유튜브" />
</a>
<a
href="https://www.instagram.com"
target="_blank"
title="인스타그램 이동"
>
<img src="assets/images/icons/ic_instagram.png" alt="인스타그램" />
</a>
</div>
</div>
</footer>
</body>
</html>
5 changes: 5 additions & 0 deletions public/images/icons/ic_delete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/images/icons/ic_plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions src/components/addItem/Description.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";

function Description({ children, name, value, placeholder, setUserInput }) {
const setDescription = (value) =>
setUserInput((prev) => ({ ...prev, description: value }));

const handleInput = ({ target }) => setDescription(target.value);

const handleBlur = ({ target }) => setDescription(target.value.trim());
return (
<div className="form-input-wrap">
<label htmlFor={`item_${name}`}>{children}</label>
<textarea
id={`item_${name}`}
placeholder={placeholder}
value={value}
onChange={handleInput}
onBlur={handleBlur}
required
/>
</div>
);
}

export default Description;
92 changes: 92 additions & 0 deletions src/components/addItem/ImgFileInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { useRef, useState } from "react";

function ImgFileInput({ children, name, setImage }) {
const input = useRef();
const [thumbnail, setThumbnail] = useState(""); // 추가한 이미지를 관리하기 위한 state
const [showWarn, setShowWarn] = useState(false); // 이미지를 1개 이상 추가하려고 할 때를 위한 state
const isFilled = thumbnail.length > 0;

/**
* form의 이미지를 저장하고 화면에 추가한 이미지를 렌더링
* @param {*} path 인코딩된 파일 스트링
*/
const setImg = (path) => {
setImage((prev) => ({ ...prev, images: [path] }));
setThumbnail(path);
};

/**
* 이미지 파일 추가 - 1개 이상인 경우 클릭 시 경고 노출
*/
const handleClick = () => {
if (!isFilled) input.current.click();
else setShowWarn(true);
};

/**
* 입력 받은 파일을 인코딩하고 저장 및 렌더링
* @param {*} e
*/
const handleFileInput = (e) => {
const imgUrl = e.target.files[0];
if (imgUrl) {
const fileReader = new FileReader();
fileReader.onload = () => {
const imgPath = fileReader.result;
setImg(imgPath);
};
fileReader.readAsDataURL(imgUrl);
}
};

/**
* 이미지 삭제
*/
const handleDelete = () => {
setImg("");
setShowWarn(false);
};

return (
<div className="form-input-wrap">
<label htmlFor={`item_${name}`}>{children}</label>
<input
ref={input}
id={`item_${name}`}
className="sr-only"
type="file"
accept="image/*"
disabled={isFilled}
onChange={handleFileInput}
/>
<div className="upload-area">
<button
className="btn-upload-img"
type="button"
title="이미지 등록"
onClick={handleClick}
>
<img src="/images/icons/ic_plus.svg" alt="이미지 등록" />
이미지 등록
</button>
{thumbnail && (
<div className="thumbnail">
<img src={thumbnail} alt="thumbnail" />
<button
type="button"
className="btn-delete-thumbnail"
onClick={handleDelete}
>
<span className="sr-only">삭제</span>
</button>
</div>
)}
</div>
{showWarn && (
<div className="error-msg">*이미지 등록은 최대 1개까지 가능합니다.</div>
)}
</div>
);
}

export default ImgFileInput;
30 changes: 30 additions & 0 deletions src/components/addItem/PriceInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import { formatPrice, formatToPrice } from "utils/formatPrice";

function PriceInput({ children, name, value, setUserInput }) {
/**
* String 타입의 입력을 금액 형식으로 formating해 input에 출력
*/
const handleInput = ({ target }) => {
const priceValue = formatToPrice(target.value);
const regExp = /^\d*$/; // 숫자만 입력 가능하게 하기 위한 정규식
if (regExp.test(priceValue)) {
setUserInput((prev) => ({ ...prev, price: +priceValue })); // form의 price state 저장할 때는 Number 타입으로 변환해서 저장
}
};
return (
<div className="form-input-wrap">
<label htmlFor={`item_${name}`}>{children}</label>
<input
id={`item_${name}`}
type="text"
placeholder="상품 가격을 입력해주세요"
value={formatPrice(value)}
onChange={handleInput}
required
/>
</div>
);
}

export default PriceInput;
Loading

0 comments on commit 75679ae

Please sign in to comment.