Skip to content

Commit

Permalink
feat(Sprint6): additems 페이지 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
wonsik3686 committed Jun 28, 2024
1 parent 7ddc648 commit 966e847
Show file tree
Hide file tree
Showing 15 changed files with 561 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

#file
visualwind.wrapper.tsx

# dependencies
/node_modules
/.pnp
Expand Down
5 changes: 4 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ function App() {
<Route path="/signup" element={<Signup />} /> */}
<Route path="faq" element={<Faq />} />
<Route path="privacy" element={<Privacy />} />
<Route path="items" element={<Items />} />
<Route path="items">
<Route index element={<Items />} />
<Route path="additems" element={<AddItems />} />
</Route>
<Route path="additems" element={<AddItems />} />
</Routes>
</BrowserRouter>
Expand Down
5 changes: 5 additions & 0 deletions src/assets/images/icons/ic_X.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 src/assets/images/icons/ic_union.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: 1 addition & 1 deletion src/components/items/SellingItems/SellingItems.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function SellingItems() {
</div>
<div className="header-selling-items-right">
<a
href="/additems"
href="/items/additems"
id="btn-add-item"
className="button btn-add-item"
>
Expand Down
1 change: 1 addition & 0 deletions src/components/navigationBar/NavigationBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function NavigationBar() {
</a> */}
<NavLink
to={'/items'}

className={({ isActive }) =>
`nav-bar-menu-link ${isActive ? 'active' : ''}`
}
Expand Down
38 changes: 38 additions & 0 deletions src/core/ui/buttons/Button/Button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.btn-default {
background-color: var(--blue);
color: #ffffff;
font-family: inherit;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 600;
border: none;
outline: none;
box-shadow: none;
cursor: pointer;
line-height: inherit;
border-radius: 8px;
padding: 12px 23px;
}

.btn-default:hover {
background-color: #1967d6;
}

.btn-default:focus {
background-color: #1251aa;
}

.btn-default:disabled {
background-color: #9ca3af;
cursor: default;
pointer-events: none;
}

.btn-default.pill-button {
font-size: 16px;
font-weight: 600;
border-radius: 999px;
padding: 14.5px 33.5px;
}
18 changes: 18 additions & 0 deletions src/core/ui/buttons/Button/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect, useRef } from 'react';
import './Button.css';
function Button({ text = '버튼', onClick = () => {}, isDisabled = false }) {
const ref = useRef();

useEffect(() => {
ref.current.disabled = isDisabled ? true : false;
}, [isDisabled]);

return (
<>
<button className="btn-default" onClick={onClick} ref={ref}>
{text}
</button>
</>
);
}
export default Button;
93 changes: 93 additions & 0 deletions src/core/ui/inputs/ImageFileInput/ImageFileInput.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.wrapper-btn-input-image-file {
display: flex;
justify-content: start;
align-items: center;
}

.card-input-image-file {
width: 168px;
height: 168px;
margin: 0 8px 0 0;
border-radius: 12px;
background-color: var(--gray-100);
display: inline-flex;
justify-content: center;
align-items: center;
}

.card-input-image-file:last-child {
margin: 0;
}

.input-image-file {
display: none;
}

.wrapper-content-btn-input-image-file {
display: inline-flex;
flex-direction: column;
align-items: center;
}

.icon-union-input-image-file {
width: 48px;
height: 48px;
margin: 0 0 12px 0;
}

.text-btn-input-image-file {
color: var(--gray-400);
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
}

.img-preview-input-image-file {
width: 100%;
height: 100%;
border-radius: 12px;
}

.btn-delete-input-image-file {
position: relative;
top: -60px;
left: -40px;
opacity: 70%;
}

.btn-delete-input-image-file:hover {
opacity: 100%;
}

.btn-delete-input-image-file:focus {
opacity: 100%;
}

@media (min-width: 768px) {
.card-input-image-file {
width: 162px;
height: 162px;
margin: 0 16px 0 0;
}

.btn-delete-input-image-file {
position: relative;
top: -60px;
left: -45px;
}
}

@media (min-width: 1280px) {
.card-input-image-file {
width: 282px;
height: 282px;
margin: 0 24px 0 0;
}

.btn-delete-input-image-file {
position: relative;
top: -110px;
left: -60px;
}
}
84 changes: 84 additions & 0 deletions src/core/ui/inputs/ImageFileInput/ImageFileInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useEffect, useRef, useState } from 'react';
import { ReactComponent as IconUnion } from '../../../../assets/images/icons/ic_union.svg';
import { ReactComponent as IconX } from '../../../../assets/images/icons/ic_X.svg';
import ImgDeafault from '../../../../assets/images/market/img_default.png';
import './ImageFileInput.css';
function ImageFileInput({
className = '',
name,
value,
initialPreview,
onChange,
}) {
const [preview, setPreview] = useState(initialPreview);
const inputRef = useRef();

const handleChange = (e) => {
const nextValue = e.target.files[0];
onChange(name, nextValue);
};

const handleClearClick = () => {
const inputNode = inputRef.current;
if (!inputNode) return;

inputNode.value = '';
onChange(name, null);
};

useEffect(() => {
if (!value) return;
const nextPreview = URL.createObjectURL(value);
setPreview(nextPreview);

return () => {
setPreview(initialPreview);
URL.revokeObjectURL(nextPreview);
};
}, [value, initialPreview]);

return (
<div className={`wrapper-btn-input-image-file ${className}`}>
{/* 추가 버튼 */}
<label htmlFor="input-image-file" className="card-input-image-file">
<div className="wrapper-content-btn-input-image-file">
<IconUnion
className="icon-union-input-image-file"
alt="이미지 등록 버튼"
/>
<div className="text-btn-input-image-file">이미지 등록</div>
</div>
</label>
<input
className="input-image-file"
type="file"
id="input-image-file"
name="imgFile"
onChange={handleChange}
ref={inputRef}
/>
{/* 미리보기 이미지 */}
{value && (
<>
<div className="card-input-image-file">
<img
src={preview || ImgDeafault}
className="img-preview-input-image-file"
alt="상품 미리보기"
/>
</div>
<button
className="btn-delete-input-image-file"
onClick={handleClearClick}
>
<IconX
className="icon-delete-input-image-file"
alt="선택 해제 버튼"
/>
</button>
</>
)}
</div>
);
}
export default ImageFileInput;
39 changes: 39 additions & 0 deletions src/core/ui/inputs/TagInput/TagInput.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.wrapper-input-tags {
display: flex;
flex-direction: column;
align-items: start;
width: 100%;
}

.wrapper-list-tag-input-tag {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
width: 100%;
margin: 0;
}

.tag-input-tag {
display: flex;
align-items: center;
margin: 12px 12px 0 0;
padding: 12px 12px 12px 16px;
border-radius: 26px;
background-color: var(--gray-100);
}

.tag-input-tag:last-child {
margin: 12px 0 0;
}

.btn-delete-tag {
color: white;
width: 20px;
height: 20px;
margin: 0 0 0 5px;
background-color: var(--gray-500);
border-radius: 10px;
font-size: 15px;
font-weight: 400;
}
59 changes: 59 additions & 0 deletions src/core/ui/inputs/TagInput/TagInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useState } from 'react';
import './TagInput.css';

function TagInput({ className = '', name, tags = [], onAdd, onRemove }) {
const [targetText, setTargetText] = useState('');

const handleChange = (e) => {
const { value } = e.target;
if (!value.trim()) return;
setTargetText(value);
};

const handlePress = (e) => {
if (e.key === 'Enter' && targetText) {
e.preventDefault();
onAdd(targetText.trim());
setTargetText('');
}
};

const handleDeleteTag = (e) => {
onRemove(e.currentTarget.parentNode.dataset.tagName);
};

return (
<>
<div className={`wrapper-input-tags ${className}`}>
<input
className="input-form-add-item"
type="text"
id={name}
name={name}
value={targetText || ''}
onChange={handleChange}
onKeyDown={handlePress}
placeholder="태그를 입력해주세요"
/>
{tags.length > 0 && (
<div className="wrapper-list-tag-input-tag">
{tags.map((tag, i) => (
<div
className="tag-input-tag"
key={`tag-item-${i}`}
data-tag-name={tag}
>
{tag}
<button className="btn-delete-tag" onClick={handleDeleteTag}>
X
</button>
</div>
))}
</div>
)}
</div>
</>
);
}

export default TagInput;
Loading

0 comments on commit 966e847

Please sign in to comment.