diff --git a/craco.config.js b/craco.config.js
index e39f09a..43d9cf8 100644
--- a/craco.config.js
+++ b/craco.config.js
@@ -10,6 +10,10 @@ module.exports = {
"@pages": path.resolve(__dirname, "src/pages"),
"@routes": path.resolve(__dirname, "src/routes"),
"@utils": path.resolve(__dirname, "src/utils"),
+ "@layouts": path.resolve(__dirname, "src/layouts"),
+ "@assets": path.resolve(__dirname, "src/assets"),
+ "@styles": path.resolve(__dirname, "src/styles"),
+ "@contexts": path.resolve(__dirname, "src/contexts"),
},
},
};
diff --git a/src/App.js b/src/App.js
deleted file mode 100644
index 491dfe5..0000000
--- a/src/App.js
+++ /dev/null
@@ -1,5 +0,0 @@
-function App() {
- return
Hello React!
;
-}
-
-export default App;
diff --git a/src/App.jsx b/src/App.jsx
new file mode 100644
index 0000000..b75fc0d
--- /dev/null
+++ b/src/App.jsx
@@ -0,0 +1,18 @@
+import { ThemeProvider } from "styled-components";
+import GlobalStyle from "@styles/GlobalStyle";
+import * as CommonStyle from "@styles/common";
+import Router from "@/routes/index";
+import ContextProvider from "@contexts";
+
+function App() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/src/apis/index.js b/src/apis/index.js
new file mode 100644
index 0000000..58d0fa3
--- /dev/null
+++ b/src/apis/index.js
@@ -0,0 +1,11 @@
+import axios from "axios";
+
+const instance = axios.create({
+ baseURL: process.env.REACT_APP_API_URL,
+ timeout: 2000,
+});
+
+export const getCarList = async (params) => {
+ const response = await instance.get("/cars", { params });
+ return response;
+};
diff --git a/src/assets/icons/back.svg b/src/assets/icons/back.svg
new file mode 100644
index 0000000..62d1f16
--- /dev/null
+++ b/src/assets/icons/back.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/icons/index.js b/src/assets/icons/index.js
new file mode 100644
index 0000000..89d0b9b
--- /dev/null
+++ b/src/assets/icons/index.js
@@ -0,0 +1,7 @@
+import { ReactComponent as Back } from "@assets/icons/back.svg";
+
+const icon = {
+ back: Back,
+};
+
+export default icon;
diff --git a/src/components/CarDetailList/List.styled.jsx b/src/components/CarDetailList/List.styled.jsx
new file mode 100644
index 0000000..9601580
--- /dev/null
+++ b/src/components/CarDetailList/List.styled.jsx
@@ -0,0 +1,39 @@
+import styled from "styled-components";
+
+const List = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+const ListHeader = styled.div`
+ display: flex;
+ height: 45px;
+ align-items: center;
+ color: ${({ theme }) => theme.COLORS.WHITE};
+ background-color: ${({ theme }) => theme.COLORS.BLUE};
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ padding-left: 20px;
+`;
+
+const ListItem = styled.li`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 48px;
+ padding: 0 20px;
+`;
+
+const Name = styled.span`
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ color: ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+const Contents = styled.span`
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ color: ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+export { List, ListHeader, ListItem, Name, Contents };
diff --git a/src/components/CarDetailList/index.jsx b/src/components/CarDetailList/index.jsx
new file mode 100644
index 0000000..a4b0d9b
--- /dev/null
+++ b/src/components/CarDetailList/index.jsx
@@ -0,0 +1,19 @@
+import * as S from "@components/CarDetailList/List.styled";
+
+const CarDetailList = ({ title, contents }) => {
+ return (
+
+ {title}
+
+ {contents.map(({ name, contents }, index) => (
+
+ {name}
+ {contents}
+
+ ))}
+
+
+ );
+};
+
+export default CarDetailList;
diff --git a/src/components/CarItem/CarItem.styled.jsx b/src/components/CarItem/CarItem.styled.jsx
new file mode 100644
index 0000000..9061662
--- /dev/null
+++ b/src/components/CarItem/CarItem.styled.jsx
@@ -0,0 +1,41 @@
+import styled from "styled-components";
+import Tag from "@components/Tag";
+
+const CarItem = styled.li`
+ position: relative;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-direction: row;
+ width: 390px;
+ height: 120px;
+ padding: 0 20px;
+ border-bottom: 1px solid ${({ theme }) => theme.COLORS.BLACK};
+ cursor: pointer;
+`;
+
+const CarInfo = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+`;
+
+const Title = styled.div`
+ display: flex;
+ flex-direction: column;
+ font-size: ${({ theme }) => theme.FONT.SIZE.BASE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+`;
+
+const Contents = styled.div`
+ display: flex;
+ flex-direction: column;
+ font-size: ${({ theme }) => theme.FONT.SIZE.SMALL};
+`;
+
+const Badge = styled(Tag)`
+ position: absolute;
+ z-index: 10;
+`;
+
+export { CarItem, CarInfo, Title, Contents, Badge };
diff --git a/src/components/CarItem/index.jsx b/src/components/CarItem/index.jsx
new file mode 100644
index 0000000..9aea2e9
--- /dev/null
+++ b/src/components/CarItem/index.jsx
@@ -0,0 +1,40 @@
+import { useNavigate } from "react-router-dom";
+
+import ROUTE_PATH from "@/routes/routerPaths";
+import Image from "@components/common/Image";
+import * as S from "@components/CarItem/CarItem.styled";
+import { useCarInfoContext } from "@contexts/carInfo";
+
+const CarItem = ({ carInfo }) => {
+ const navigate = useNavigate();
+ const { setSelectedCarInfo } = useCarInfoContext();
+
+ const { id, amount, attribute } = carInfo;
+ const { brand, name, segment, imageUrl, fuelType } = attribute;
+
+ const handleClick = () => {
+ setSelectedCarInfo(carInfo);
+ navigate(`${ROUTE_PATH.DETAIL}/${id}`);
+ };
+
+ const isNew = false;
+
+ return (
+
+
+
+ {brand}
+ {name}
+
+
+ {`${segment} / ${fuelType}`}
+ {`월 ${amount.toLocaleString()} 원 부터`}
+
+
+
+ {isNew && }
+
+ );
+};
+
+export default CarItem;
diff --git a/src/components/Category/Category.styled.jsx b/src/components/Category/Category.styled.jsx
new file mode 100644
index 0000000..ac9af27
--- /dev/null
+++ b/src/components/Category/Category.styled.jsx
@@ -0,0 +1,18 @@
+import styled from "styled-components";
+
+const Category = styled.ul`
+ display: flex;
+ width: 100%;
+ height: 40px;
+ overflow-x: scroll;
+ gap: 8px;
+ border-bottom: 1px solid ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+const CategoryItem = styled.li`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+export { Category, CategoryItem };
diff --git a/src/components/Category/index.jsx b/src/components/Category/index.jsx
new file mode 100644
index 0000000..6bb414d
--- /dev/null
+++ b/src/components/Category/index.jsx
@@ -0,0 +1,23 @@
+import * as S from "@components/Category/Category.styled";
+import Tag from "@components/Tag";
+import { useCategoryContext } from "@contexts/category";
+
+const Category = ({ categories }) => {
+ const { selectedCategory, setSelectedCategory } = useCategoryContext();
+
+ const handleClick = ({ target }) => {
+ setSelectedCategory(target.id);
+ };
+
+ return (
+
+ {categories.map(({ id, name }) => (
+
+
+
+ ))}
+
+ );
+};
+
+export default Category;
diff --git a/src/components/Tag/Tag.styled.jsx b/src/components/Tag/Tag.styled.jsx
new file mode 100644
index 0000000..8668770
--- /dev/null
+++ b/src/components/Tag/Tag.styled.jsx
@@ -0,0 +1,36 @@
+import styled, { css, ThemeConsumer } from "styled-components";
+
+const ITEM_TAG_STYLE = css`
+ width: 52px;
+ height: 22px;
+ border-radius: 42px;
+ font-size: ${({ theme }) => theme.FONT.SIZE.SMALL};
+ color: ${({ theme }) => theme.COLORS.WHITE};
+ background-color: ${({ theme }) => theme.COLORS.BLUE};
+`;
+
+const DEFAULT_TAG_STYLE = css`
+ width: 62px;
+ height: 27px;
+ border-radius: 62px;
+ font-size: ${({ theme }) => theme.FONT.SIZE.BASE};
+ color: ${({ isSelected, theme }) => (isSelected ? theme.COLORS.WHITE : theme.COLORS.BLACK)};
+ background-color: ${({ isSelected, theme }) =>
+ isSelected ? theme.COLORS.BLACK : theme.COLORS.GREY};
+`;
+
+const TAG_STYLE = {
+ small: ITEM_TAG_STYLE,
+ default: DEFAULT_TAG_STYLE,
+};
+
+const Tag = styled.button`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ ${({ size = "default" }) => TAG_STYLE[size]}
+`;
+
+export { Tag };
diff --git a/src/components/Tag/index.jsx b/src/components/Tag/index.jsx
new file mode 100644
index 0000000..61760dd
--- /dev/null
+++ b/src/components/Tag/index.jsx
@@ -0,0 +1,11 @@
+import * as S from "@components/Tag/Tag.styled";
+
+const Tag = ({ size = "default", id, name, isSelected, onClick }) => {
+ return (
+
+ {name}
+
+ );
+};
+
+export default Tag;
diff --git a/src/components/common/Icon/index.jsx b/src/components/common/Icon/index.jsx
new file mode 100644
index 0000000..81804f9
--- /dev/null
+++ b/src/components/common/Icon/index.jsx
@@ -0,0 +1,8 @@
+import icon from "@/assets/icons/index";
+
+const Icon = ({ iconName }) => {
+ const IconComponent = icon[iconName];
+ return ;
+};
+
+export default Icon;
diff --git a/src/components/common/Image/Image.styled.jsx b/src/components/common/Image/Image.styled.jsx
new file mode 100644
index 0000000..b0b3c53
--- /dev/null
+++ b/src/components/common/Image/Image.styled.jsx
@@ -0,0 +1,23 @@
+import styled, { css } from "styled-components";
+
+const BIG_IMAGE = css`
+ width: 390px;
+ height: 205px;
+`;
+
+const DEFAULT_IMAGE = css`
+ width: 152px;
+ height: 80px;
+`;
+
+const IMAGE_STYLE = {
+ default: DEFAULT_IMAGE,
+ big: BIG_IMAGE,
+};
+
+const Image = styled.img`
+ object-fit: cover;
+ ${({ size = "default" }) => IMAGE_STYLE[size]}
+`;
+
+export { Image };
diff --git a/src/components/common/Image/index.jsx b/src/components/common/Image/index.jsx
new file mode 100644
index 0000000..4460353
--- /dev/null
+++ b/src/components/common/Image/index.jsx
@@ -0,0 +1,4 @@
+import * as S from "@components/common/Image/Image.styled";
+const Image = ({ url, size = "default" }) => ;
+
+export default Image;
diff --git a/src/constants/carInfo.js b/src/constants/carInfo.js
new file mode 100644
index 0000000..7aa812f
--- /dev/null
+++ b/src/constants/carInfo.js
@@ -0,0 +1,12 @@
+export const SEGMENT = {
+ C: "소형",
+ D: "중형",
+ E: "대형",
+ SUV: "SUV",
+};
+
+export const FUEL_TYPE = {
+ gasoline: "가솔린",
+ ev: "전기",
+ hybrid: "하이브리드",
+};
diff --git a/src/contexts/carInfo.jsx b/src/contexts/carInfo.jsx
new file mode 100644
index 0000000..a553cd1
--- /dev/null
+++ b/src/contexts/carInfo.jsx
@@ -0,0 +1,20 @@
+import { createContext, useContext, useState } from "react";
+
+const CarInfoContext = createContext();
+CarInfoContext.displayName = "CarInfoContext";
+
+const useCarInfoContext = () => {
+ const context = useContext(CarInfoContext);
+ if (!context) {
+ throw new Error("useCarInfoContext should be used within CarInfoContext.Provider");
+ }
+ return context;
+};
+
+const CarInfoProvider = ({ children }) => {
+ const [selectedCarInfo, setSelectedCarInfo] = useState();
+ const value = { selectedCarInfo, setSelectedCarInfo };
+ return {children};
+};
+
+export { useCarInfoContext, CarInfoProvider };
diff --git a/src/contexts/category.jsx b/src/contexts/category.jsx
new file mode 100644
index 0000000..e94dfe0
--- /dev/null
+++ b/src/contexts/category.jsx
@@ -0,0 +1,20 @@
+import { createContext, useContext, useState } from "react";
+
+const CategoryContext = createContext();
+CategoryContext.displayName = "CategoryContext";
+
+const useCategoryContext = () => {
+ const context = useContext(CategoryContext);
+ if (!context) {
+ throw new Error("useCategoryContext should be used within CategoryContext.Provider");
+ }
+ return context;
+};
+
+const CategoryProvider = ({ children }) => {
+ const [selectedCategory, setSelectedCategory] = useState("all");
+ const value = { selectedCategory, setSelectedCategory };
+ return {children};
+};
+
+export { useCategoryContext, CategoryProvider };
diff --git a/src/contexts/index.jsx b/src/contexts/index.jsx
new file mode 100644
index 0000000..fecefb1
--- /dev/null
+++ b/src/contexts/index.jsx
@@ -0,0 +1,10 @@
+import { CarInfoProvider } from "@contexts/carInfo";
+import { CategoryProvider } from "@contexts/category";
+
+const ContextProvider = ({ children }) => (
+
+ {children}
+
+);
+
+export default ContextProvider;
diff --git a/src/hooks/useFetch.jsx b/src/hooks/useFetch.jsx
new file mode 100644
index 0000000..2cd1514
--- /dev/null
+++ b/src/hooks/useFetch.jsx
@@ -0,0 +1,24 @@
+import { useState } from "react";
+
+const useFetch = (apiFunc) => {
+ const [isFetching, setFetching] = useState(false);
+ const [data, setResponse] = useState();
+
+ const fetch = (params) => {
+ setFetching(() => {
+ apiFunc(params)
+ .then(({ data }) => {
+ setResponse(data.payload);
+ setFetching(false);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ return true;
+ });
+ };
+
+ return { isFetching, fetch, data };
+};
+
+export default useFetch;
diff --git a/src/index.js b/src/index.jsx
similarity index 99%
rename from src/index.js
rename to src/index.jsx
index a64e7d5..110ab10 100644
--- a/src/index.js
+++ b/src/index.jsx
@@ -1,5 +1,6 @@
import React from "react";
import ReactDOM from "react-dom/client";
+
import "./index.css";
import App from "./App";
diff --git a/src/layouts/Header/Header.styled.jsx b/src/layouts/Header/Header.styled.jsx
new file mode 100644
index 0000000..f22a2dc
--- /dev/null
+++ b/src/layouts/Header/Header.styled.jsx
@@ -0,0 +1,27 @@
+import styled from "styled-components";
+
+const Header = styled.div`
+ display: flex;
+ align-items: center;
+ position: relative;
+ min-width: 360px;
+ width: 450px;
+ height: 60px;
+ border-bottom: 1px solid ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+const Title = styled.h1`
+ width: 100%;
+ text-align: center;
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ color: ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+const IconWrapper = styled.div`
+ position: absolute;
+ z-index: 10;
+ left: 20px;
+`;
+
+export { Header, Title, IconWrapper };
diff --git a/src/layouts/Header/index.jsx b/src/layouts/Header/index.jsx
new file mode 100644
index 0000000..fad77fc
--- /dev/null
+++ b/src/layouts/Header/index.jsx
@@ -0,0 +1,32 @@
+import * as S from "@layouts/Header/Header.styled";
+import Icon from "@/components/common/Icon/index";
+import { useLocation, useNavigate } from "react-router-dom";
+import ROUTE_PATH from "@/routes/routerPaths";
+
+const TITLE = {
+ HOME: "전체차량",
+ DETAIL: "차량상세",
+};
+
+const Header = () => {
+ const { pathname } = useLocation();
+ const isHome = pathname === ROUTE_PATH.BASE;
+
+ const navigate = useNavigate();
+ const handleClick = () => {
+ navigate(`${ROUTE_PATH.BASE}`);
+ };
+
+ return (
+
+ {!isHome && (
+
+
+
+ )}
+ {isHome ? TITLE.HOME : TITLE.DETAIL}
+
+ );
+};
+
+export default Header;
diff --git a/src/layouts/index.jsx b/src/layouts/index.jsx
new file mode 100644
index 0000000..327333b
--- /dev/null
+++ b/src/layouts/index.jsx
@@ -0,0 +1,23 @@
+import { Outlet } from "react-router-dom";
+import styled from "styled-components";
+
+import Header from "@layouts/Header/index";
+
+const Layout = () => {
+ return (
+
+
+
+
+ );
+};
+
+const LayoutContainer = styled.div`
+ display: flex;
+ position: relative;
+ align-items: center;
+ flex-direction: column;
+ height: 100vh;
+`;
+
+export default Layout;
diff --git a/src/pages/CarDetail/CarDetail.styled.jsx b/src/pages/CarDetail/CarDetail.styled.jsx
new file mode 100644
index 0000000..4cfa529
--- /dev/null
+++ b/src/pages/CarDetail/CarDetail.styled.jsx
@@ -0,0 +1,56 @@
+import styled, { css } from "styled-components";
+
+const CarDetail = styled.div`
+ display: flex;
+ flex-direction: column;
+ min-width: 360px;
+ width: 450px;
+`;
+
+const Thumbnail = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 206px;
+`;
+
+const TitleWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 92px;
+ padding: 0 20px;
+`;
+
+const MAIN_TITLE_STYLE = css`
+ font-size: ${({ theme }) => theme.FONT.SIZE.X_LARGE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ text-align: left;
+`;
+
+const SUB_TITLE_STYLE = css`
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ text-align: left;
+`;
+
+const AMOUNT_TITLE_STYLE = css`
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.REGULAR};
+ text-align: right;
+ padding: 13px 20px 13px 0;
+`;
+
+const titleStyle = {
+ main: MAIN_TITLE_STYLE,
+ sub: SUB_TITLE_STYLE,
+ amount: AMOUNT_TITLE_STYLE,
+};
+
+const Title = styled.span`
+ width: 100%;
+ ${({ type }) => titleStyle[type]}
+`;
+
+export { CarDetail, Thumbnail, TitleWrapper, Title };
diff --git a/src/pages/CarDetail/index.jsx b/src/pages/CarDetail/index.jsx
new file mode 100644
index 0000000..94a59d0
--- /dev/null
+++ b/src/pages/CarDetail/index.jsx
@@ -0,0 +1,59 @@
+import { useCarInfoContext } from "../../contexts/carInfo";
+import * as S from "@pages/CarDetail/CarDetail.styled";
+import Image from "../../components/common/Image/index";
+import { FUEL_TYPE, SEGMENT } from "../../constants/carInfo";
+import CarDetailList from "../../components/CarDetailList";
+
+const CarDetail = () => {
+ const { selectedCarInfo: carInfo } = useCarInfoContext();
+ const { amount } = carInfo;
+ const { brand, name, imageUrl } = carInfo.attribute;
+ const carContents = createCarContents(carInfo);
+
+ return (
+
+
+
+
+
+ {brand}
+ {name}
+ {`월 ${amount.toLocaleString()}원`}
+
+ {Object.keys(carContents).map((title) => (
+
+ ))}
+
+ );
+};
+
+const createCarContents = (carInfo) => {
+ const { startDate, insurance, additionalProducts } = carInfo;
+ const { segment, fuelType } = carInfo.attribute;
+
+ const carContents = {
+ "차량 정보": [
+ { name: "차종", contents: SEGMENT[segment] },
+ { name: "연료", contents: FUEL_TYPE[fuelType] },
+ { name: "이용 가능일", contents: startDate },
+ ],
+ };
+
+ if (insurance && insurance.length > 0) {
+ carContents["보험"] = insurance.map(({ name, description }) => ({
+ name,
+ contents: description,
+ }));
+ }
+
+ if (additionalProducts && additionalProducts.length > 0) {
+ carContents["추가 상품"] = additionalProducts.map(({ name, amount }) => ({
+ name,
+ contents: `월 ${amount.toLocaleString()}원`,
+ }));
+ }
+
+ return carContents;
+};
+
+export default CarDetail;
diff --git a/src/pages/Home/Home.styled.jsx b/src/pages/Home/Home.styled.jsx
new file mode 100644
index 0000000..f8d43b0
--- /dev/null
+++ b/src/pages/Home/Home.styled.jsx
@@ -0,0 +1,20 @@
+import styled from "styled-components";
+
+const Home = styled.div`
+ min-width: 360px;
+ width: 450px;
+ height: 100%;
+`;
+
+const BackgroundMsg = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ font-weight: ${({ theme }) => theme.FONT.WEIGHT.BOLD};
+ font-size: ${({ theme }) => theme.FONT.SIZE.LARGE};
+ color: ${({ theme }) => theme.COLORS.BLACK};
+`;
+
+export { Home, BackgroundMsg };
diff --git a/src/pages/Home/index.jsx b/src/pages/Home/index.jsx
new file mode 100644
index 0000000..38ec90d
--- /dev/null
+++ b/src/pages/Home/index.jsx
@@ -0,0 +1,60 @@
+import * as S from "@pages/Home/Home.styled";
+import Category from "@components/Category/index";
+import { useEffect, useState } from "react";
+import { useCategoryContext } from "@/contexts/category";
+import { getCarList } from "@/apis/index";
+import CarItem from "@/components/CarItem/index";
+import useFetch from "../../hooks/useFetch";
+
+const categories = [
+ {
+ id: "all",
+ name: "전체",
+ },
+ {
+ id: "C",
+ name: "소형",
+ },
+ {
+ id: "D",
+ name: "중형",
+ },
+ {
+ id: "E",
+ name: "대형",
+ },
+];
+
+const Home = () => {
+ const { fetch, isFetching, data: carList } = useFetch(getCarList);
+ const { selectedCategory } = useCategoryContext();
+ const [backgroundMsg, setBackgroundMsg] = useState("");
+
+ useEffect(() => {
+ const params = selectedCategory !== "all" ? { segment: selectedCategory } : {};
+ fetch(params);
+ }, [selectedCategory]);
+
+ useEffect(() => {
+ if (isFetching) {
+ setBackgroundMsg("불러오는 중");
+ return;
+ }
+
+ if (!carList || carList.length === 0) {
+ setBackgroundMsg("차량이 없습니다!");
+ } else {
+ setBackgroundMsg("");
+ }
+ }, [isFetching, carList]);
+
+ return (
+
+
+ {!isFetching && carList && carList.map((data) => )}
+ {backgroundMsg !== "" && {backgroundMsg}}
+
+ );
+};
+
+export default Home;
diff --git a/src/routes/index.jsx b/src/routes/index.jsx
new file mode 100644
index 0000000..dae6339
--- /dev/null
+++ b/src/routes/index.jsx
@@ -0,0 +1,21 @@
+import { BrowserRouter, Route, Routes } from "react-router-dom";
+import ROUTE_PATH from "@/routes/routerPaths";
+import Layout from "@/layouts";
+import Home from "@/pages/Home";
+import CarDetail from "../pages/CarDetail/index";
+
+const Router = () => {
+ return (
+
+
+ }>
+ } />
+ } />
+ NOT FOUND} />
+
+
+
+ );
+};
+
+export default Router;
diff --git a/src/routes/routerPaths.js b/src/routes/routerPaths.js
new file mode 100644
index 0000000..143deaf
--- /dev/null
+++ b/src/routes/routerPaths.js
@@ -0,0 +1,7 @@
+const ROUTE_PATH = {
+ BASE: process.env.REACT_APP_BASE_URL || "/",
+ DETAIL: "/detail",
+ NOT_FOUND: "*",
+};
+
+export default ROUTE_PATH;
diff --git a/src/styles/GlobalStyle.js b/src/styles/GlobalStyle.js
new file mode 100644
index 0000000..aa4940e
--- /dev/null
+++ b/src/styles/GlobalStyle.js
@@ -0,0 +1,20 @@
+import { createGlobalStyle } from "styled-components";
+
+export default createGlobalStyle`
+
+html {
+ font-size: 62.5%;
+}
+
+ol,
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ border: 0;
+ outline: 0;
+}
+`;
diff --git a/src/styles/common/color.js b/src/styles/common/color.js
new file mode 100644
index 0000000..df7fdbb
--- /dev/null
+++ b/src/styles/common/color.js
@@ -0,0 +1,8 @@
+const COLORS = {
+ BLACK: "#000000",
+ GREY: "#D9D9D9",
+ BLUE: "#0094FF",
+ WHITE: "#FFFFFF",
+};
+
+export default COLORS;
diff --git a/src/styles/common/font.js b/src/styles/common/font.js
new file mode 100644
index 0000000..0a8b5ab
--- /dev/null
+++ b/src/styles/common/font.js
@@ -0,0 +1,20 @@
+const FONT_SIZE = {
+ X_LARGE: "2.4rem",
+ LARGE: "1.8rem",
+ BASE: "1.4rem",
+ SMALL: "1.2rem",
+};
+
+const FONT_WEIGHT = {
+ BOLD: "700",
+ MEDIUM: "500",
+ REGULAR: "400",
+ LIGHT: "100",
+};
+
+const FONT = {
+ SIZE: FONT_SIZE,
+ WEIGHT: FONT_WEIGHT,
+};
+
+export default FONT;
diff --git a/src/styles/common/index.js b/src/styles/common/index.js
new file mode 100644
index 0000000..e75a6d2
--- /dev/null
+++ b/src/styles/common/index.js
@@ -0,0 +1,4 @@
+import COLORS from "@styles/common/color";
+import FONT from "@styles/common/font";
+
+export { COLORS, FONT };