Skip to content

Commit

Permalink
refactoring to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
joodongkim committed Oct 18, 2024
2 parents 0c5bb5c + 0b131e7 commit 1fe9f12
Show file tree
Hide file tree
Showing 24 changed files with 1,746 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { BrowserRouter, Route, Routes } from "react-router-dom";
import HomePage from "./pages/HomePage/HomePage";
import LoginPage from "./pages/LoginPage/LoginPage";
import MarketPage from "./pages/MarketPage/MarketPage";
import AddItemPage from "./pages/AddItemPage/AddItemPage";
import CommunityFeedPage from "./pages/CommunityFeedPage/CommunityFeedPage";
import Header from "./components/Layout/Header";
import ItemPage from "./pages/ItemPage/ItemPage";

function App() {
return (
<BrowserRouter>
<Header />

<div className="withHeader">
<Routes>
<Route index element={<HomePage />} />
<Route path="login" element={<LoginPage />} />
<Route path="items" element={<MarketPage />} />
<Route path="items/:productId" element={<ItemPage />} />
<Route path="additem" element={<AddItemPage />} />
<Route path="community" element={<CommunityFeedPage />} />
</Routes>
</div>
</BrowserRouter>
);
}

export default App;
45 changes: 45 additions & 0 deletions src/components/Layout/Header.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.headerLeft {
display: flex;
align-items: center;
}

.headerLogo {
margin-right: 16px;
}

.globalHeader nav ul {
display: flex;
list-style: none;
gap: 8px;
font-weight: bold;
font-size: 16px;
color: var(--gray-600);
}

.globalHeader nav ul li a:hover {
color: var(--blue);
}

.loginLink {
font-size: 16px;
font-weight: 600;
border-radius: 8px;
padding: 11.5px 23px;
}

@media (min-width: 768px) {
.globalHeader nav ul {
gap: 36px;
font-size: 18px;
}

.headerLogo {
margin-right: 35px;
}
}

@media (min-width: 1280px) {
.headerLogo {
margin-right: 47px;
}
}
50 changes: 50 additions & 0 deletions src/components/Layout/Header.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import Logo from "../../assets/images/logo/logo.svg";
import { Link, NavLink, useLocation } from "react-router-dom";
import "./Header.css";

function getLinkStyle({ isActive }) {
return { color: isActive ? "var(--blue)" : undefined };
}

function Header() {
const location = useLocation(); // 현재 경로 정보

return (
<header className="globalHeader">
<div className="headerLeft">
<Link to="/" className="headerLogo" aria-label="홈으로 이동">
<img src={Logo} alt="판다마켓 로고" width="153" />
</Link>

<nav>
<ul>
<li>
<NavLink to="/community" style={getLinkStyle}>
자유게시판
</NavLink>
</li>
<li>
<NavLink
to="/items"
style={({ isActive }) =>
location.pathname === "/additem" || isActive
? { color: "var(--blue)" }
: {}
}
>
중고마켓
</NavLink>
</li>
</ul>
</nav>
</div>

<Link to="/login" className="loginLink button">
로그인
</Link>
</header>
);
}

export default Header;
33 changes: 33 additions & 0 deletions src/components/UI/DropdownMenu.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.sortButtonWrapper {
position: relative;
}

.sortDropdownTriggerButton {
border: 1px solid var(--gray-200);
border-radius: 12px;
padding: 9px;
margin-left: 8px;
}

.dropdownMenu {
position: absolute;
top: 110%;
right: 0;
background: #fff;
border-radius: 8px;
border: 1px solid var(--gray-200);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 99;
}

.dropdownItem {
padding: 12px 44px;
border-bottom: 1px solid var(--gray-200);
font-size: 16px;
color: var(--gray-800);
cursor: pointer;
}

.dropdownItem:last-child {
border-bottom: none;
}
32 changes: 32 additions & 0 deletions src/components/UI/Icon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import styled from 'styled-components'

const IconWrapper = styled.div`
display: inline-flex;
align-items: center;
justify-content: center;
svg {
fill: ${({ $fillColor }) => $fillColor || 'current'}; // 색 채움
width: ${({ $size }) => ($size ? `${$size}px` : 'auto')};
height: ${({ $size }) => ($size ? `${$size}px` : 'auto')};
}
svg path {
stroke: ${({ $fillColor, $outlineColor }) =>
$fillColor || $outlineColor || 'currentColor'};
}
`

const Icon = ({
iconComponent: IconComponent,
size,
fillColor,
outlineColor
}) => (
<IconWrapper $size={size} $fillColor={fillColor} $outlineColor={outlineColor}>
<IconComponent />
</IconWrapper>
)

export default Icon
76 changes: 76 additions & 0 deletions src/components/UI/InputItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from "react";
import styled, { css } from "styled-components";

const inputStyle = css`
padding: 16px 24px;
background-color: ${({ theme }) => theme.colors.gray[100]};
color: ${({ theme }) => theme.colors.gray[800]};
border: none;
border-radius: 12px;
font-size: 16px;
line-height: 24px;
width: 100%;
&::placeholder {
color: ${({ theme }) => theme.colors.gray[400]};
}
&:focus {
outline-color: ${({ theme }) => theme.colors.blue.primary};
}
`;

export const Label = styled.label`
display: block;
font-size: 14px;
font-weight: bold;
margin-bottom: 12px;
@media ${({ theme }) => theme.mediaQuery.tablet} {
font-size: 18px;
}
`;

const InputField = styled.input`
${inputStyle}
`;

const TextArea = styled.textarea`
${inputStyle}
height: 200px;
resize: none;
`;

function InputItem({
id,
label,
value,
onChange,
placeholder,
onKeyDown,
isTextArea,
}) {
return (
<div>
{label && <Label htmlFor={id}>{label}</Label>}
{isTextArea ? (
<TextArea
id={id}
value={value}
onChange={onChange}
placeholder={placeholder}
/>
) : (
<InputField
id={id}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
placeholder={placeholder}
/>
)}
</div>
);
}

export default InputItem;
52 changes: 52 additions & 0 deletions src/components/UI/LoadingSpinner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { PulseLoader } from 'react-spinners'

const MaskedBackground = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 9998;
`

const SpinnerOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.2);
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
`

const LoadingSpinner = ({
size = 20,
color = 'var(--blue)',
minLoadTime = 500
}) => {
const [isVisible, setIsVisible] = useState(true)

useEffect(() => {
const timer = setTimeout(() => {
setIsVisible(false)
}, minLoadTime)

return () => clearTimeout(timer)
}, [minLoadTime])

return isVisible ? (
<MaskedBackground>
<SpinnerOverlay>
<PulseLoader size={size} color={color} />
</SpinnerOverlay>
</MaskedBackground>
) : null
}

export default LoadingSpinner
29 changes: 29 additions & 0 deletions src/components/UI/PaginationBar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.paginationBar {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}

.paginationButton {
border: 1px solid var(--gray-200);
border-radius: 50%;
width: 40px;
height: 40px;
color: var(--gray-500);
font-weight: 600;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}

.paginationButton:disabled {
cursor: default;
opacity: 0.5;
}

.paginationButton.active {
background-color: var(--blue);
color: #fff;
}
Loading

0 comments on commit 1fe9f12

Please sign in to comment.