From 81aa73be9cec9fbbd7fe582aa27922a718e92e1d Mon Sep 17 00:00:00 2001 From: leejuhi <163210518+leejuhi@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:52:15 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=EC=84=B8=EB=B6=80=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 추가 --- eslint.config.js | 1 + src/components/Building.tsx | 59 +++++++++++++++++++++++-- src/components/BuildingDetail.tsx | 66 ++++++++++++++++++++++++++++ src/components/Divider.tsx | 11 +++++ src/components/HomeBoard.tsx | 14 +++++- src/components/data/buildingData.ts | 22 ++++++++++ src/components/style/GlobalStyle.tsx | 1 + 7 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 src/components/BuildingDetail.tsx create mode 100644 src/components/Divider.tsx create mode 100644 src/components/data/buildingData.ts diff --git a/eslint.config.js b/eslint.config.js index 0387e22..27c452e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -20,6 +20,7 @@ export default [ "react/react-in-jsx-scope": "off", // React 17 이상에서는 불필요 "react/jsx-no-target-blank": ["error", { allowReferrer: true }], // 보안 문제 해결 "@typescript-eslint/no-explicit-any": "off", + "react/prop-types": "off", }, }, ]; diff --git a/src/components/Building.tsx b/src/components/Building.tsx index d2f788b..2b5ce14 100644 --- a/src/components/Building.tsx +++ b/src/components/Building.tsx @@ -1,21 +1,72 @@ import styled from "@emotion/styled"; - +import Divider from "./Divider.tsx"; +import { buildingData, BuildingInfo } from "./data/buildingData.ts"; const Container = styled.div` + width: 400px; position: relative; - padding: 45px; + padding: 20px 30px; overflow: hidden; `; const Title = styled.div` + margin: 10px 0px; width: 300px; - font-size: 30px; + font-size: 35px; font-weight: 600; `; -const Building = () => { +const SubTitle = styled.div` + font-size: 25px; + font-weight: 500; + margin: 10px 0px; +`; +const BuildingItem = styled.a` + display: flex; + margin: 20px 0px; + color: black; +`; +const Image = styled.img` + width: 100px; + height: 100px; + margin-right: 20px; +`; +const Detail = styled.div` + display: flex; + flex-direction: column; + gap: 10px; +`; +const Name = styled.div` + font-size: 20px; + font-weight: 500; +`; + +interface BuildingProps { + onBuildingClick: (building: BuildingInfo) => void; +} +const Building: React.FC = ({ onBuildingClick }) => { return ( <> 홍익대학교 + + + 내부건물 + {buildingData.map((building) => ( + <> + onBuildingClick(building)} + > + + + {building.name} +
운영 시간: {building.time}
+
+
+ + + ))} +
); }; diff --git a/src/components/BuildingDetail.tsx b/src/components/BuildingDetail.tsx new file mode 100644 index 0000000..d386c09 --- /dev/null +++ b/src/components/BuildingDetail.tsx @@ -0,0 +1,66 @@ +import styled from "@emotion/styled"; +import { BuildingInfo } from "./data/buildingData"; +import Divider from "./Divider"; +import { useState } from "react"; + +interface BuildingDetailProps { + building: BuildingInfo; +} +const Image = styled.img` + width: 100%; + height: 220px; + object-fit: cover; +`; +const Container = styled.div` + width: 400px; + padding: 20px; +`; +const DropDown = styled.select` + border: none; + margin: 10px 0px; + width: 100px; + padding: 4px 5px; + text-align: left; + border-radius: 10px; + font-size: 13.5px; + background: #a7a7a7; + color: white; + appearance: none; +`; +const FloorDetail = styled.div` + padding: 20px; + width: 400px; +`; +const BuildingDetail: React.FC = ({ building }) => { + const [selectedFloor, setSelectedFloor] = useState(null); + + const handleFloorChange = (event: React.ChangeEvent) => { + setSelectedFloor(event.target.value); + }; + return ( + <> + {building.name} + +

{building.name}

+

운영 시간: {building.time}

+ + + {building.floors.map((floor) => ( + + ))} + +
+ + {selectedFloor && ( + +

{selectedFloor} 정보

+

여기에 {selectedFloor}에 대한 정보를 추가하세요.

+
+ )} + + ); +}; + +export default BuildingDetail; diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx new file mode 100644 index 0000000..8be5d48 --- /dev/null +++ b/src/components/Divider.tsx @@ -0,0 +1,11 @@ +import styled from "@emotion/styled"; +interface DividerProps { + size: boolean; +} +const Divider = styled.div` + width: 100%; + height: ${({ size }) => (size ? "10px" : "1px")}; + background: #e9e9e9; +`; + +export default Divider; diff --git a/src/components/HomeBoard.tsx b/src/components/HomeBoard.tsx index 7f11700..bdad230 100644 --- a/src/components/HomeBoard.tsx +++ b/src/components/HomeBoard.tsx @@ -2,6 +2,8 @@ import styled from "@emotion/styled"; import { useState } from "react"; import { IoIosArrowBack, IoIosArrowForward } from "react-icons/io"; import Building from "./Building"; +import { BuildingInfo } from "./data/buildingData.ts"; +import BuildingDetail from "./BuildingDetail.tsx"; interface PanelProps { isOpen: boolean; } @@ -53,11 +55,15 @@ const Button = styled.button` font-size: 17px; `; -const HomeBoard: React.FC = () => { +const HomeBoard = () => { const [isOpen, setIsOpen] = useState(false); + const [building, setBuilding] = useState(null); const toggleMenu = () => { setIsOpen(!isOpen); }; + const handleClick = (building: BuildingInfo) => { + setBuilding(building); + }; return ( <> @@ -84,7 +90,11 @@ const HomeBoard: React.FC = () => { )} - + {building ? ( + + ) : ( + + )} diff --git a/src/components/data/buildingData.ts b/src/components/data/buildingData.ts new file mode 100644 index 0000000..4649a3f --- /dev/null +++ b/src/components/data/buildingData.ts @@ -0,0 +1,22 @@ +export interface BuildingInfo { + image: string; + name: string; + time: string; + floors: string[]; +} + +export const buildingData: BuildingInfo[] = [ + { + image: + "https://photo.hongik.ac.kr/app/board/attach/image/thumb_353_1697760691000.do", + name: "홍문관", + time: "10:00~18:00", + floors: ["1층", "2층", "3층", "4층", "5층", "6층", "7층", "8층"], + }, + { + image: "https://www.hongik.ac.kr/front/images/local/common/logo.png", + name: "와우관", + time: "00:00~24:00", + floors: ["1층", "2층", "3층", "4층", "5층", "6층", "7층", "8층"], + }, +]; diff --git a/src/components/style/GlobalStyle.tsx b/src/components/style/GlobalStyle.tsx index 4cf0edb..b305a7d 100644 --- a/src/components/style/GlobalStyle.tsx +++ b/src/components/style/GlobalStyle.tsx @@ -10,6 +10,7 @@ const GlobalStyle = () => ( box-sizing: border-box; margin: 0px; padding: 0px; + text-decoration: none; } body { margin-left: 70px; From 2224fdec253de28880c8297b60b58a2a09aa440d Mon Sep 17 00:00:00 2001 From: leejuhi <163210518+leejuhi@users.noreply.github.com> Date: Wed, 15 Jan 2025 02:17:06 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EB=82=B4=EB=B6=80=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=20=EC=84=A0=ED=83=9D=20=EC=B0=BD=20=ED=88=B4=20?= =?UTF-8?q?=EC=9E=A1=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 툴잡기 --- src/App.tsx | 1 + src/components/BuildingDetail.tsx | 114 ++++++++++++++++++++++++++---- src/components/FacilityDetail.tsx | 9 +++ 3 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 src/components/FacilityDetail.tsx diff --git a/src/App.tsx b/src/App.tsx index c2276ee..7e1d97e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,6 +11,7 @@ function App() { } /> + diff --git a/src/components/BuildingDetail.tsx b/src/components/BuildingDetail.tsx index d386c09..24cca2e 100644 --- a/src/components/BuildingDetail.tsx +++ b/src/components/BuildingDetail.tsx @@ -2,34 +2,108 @@ import styled from "@emotion/styled"; import { BuildingInfo } from "./data/buildingData"; import Divider from "./Divider"; import { useState } from "react"; - +const FacilityItems = styled.div` + display: flex; + padding: 20px 0px; + flex-direction: column; +`; +const TitleItems = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +`; +const StoreButton = styled.button` + border: none; + background: #8099b1; + color: white; + padding: 2px; + width: 50px; + height: 27px; + border-radius: 10px; + font-size: 13px; + font-weight: 300; + cursor: pointer; + white-space: nowrap; + &:hover { + background: rgb(0, 51, 99, 0.8); + } +`; +const Facilities = styled.div` + display: flex; + gap: 10px; +`; +const DetailTitle = styled.p` + font-size: 20px; + font-weight: 500; + margin: 10px 0px; +`; +const Button = styled.button` + border: none; + background: #a7a7a7; + color: white; + padding: 5px 10px; + border-radius: 10px; + font-size: 18px; + font-weight: 300; + width: 84px; + cursor: pointer; + flex-shrink: 0; + white-space: nowrap; + &:hover { + background: rgb(0, 51, 99, 0.5); + } +`; interface BuildingDetailProps { building: BuildingInfo; } const Image = styled.img` width: 100%; - height: 220px; + height: 200px; object-fit: cover; `; const Container = styled.div` width: 400px; - padding: 20px; + padding: 20px 30px; `; const DropDown = styled.select` border: none; margin: 10px 0px; width: 100px; - padding: 4px 5px; + padding: 4px 15px; text-align: left; border-radius: 10px; font-size: 13.5px; + font-weight: 300; background: #a7a7a7; color: white; appearance: none; `; -const FloorDetail = styled.div` - padding: 20px; - width: 400px; +const Review = styled.div` + font-size: 15px; + font-weight: 300; + color: #a7a7a7; +`; +const Like = styled.div` + display: flex; + gap: 10px; + margin: 15px 0px 10px 0px; +`; + +const LikeButton = styled.button` + border: none; + background: rgb(0, 51, 99, 0.2); + color: black; + padding: 5px 10px; + border-radius: 10px; + font-size: 13px; + font-weight: 300; + cursor: pointer; + white-space: nowrap; + &:hover { + background: rgb(0, 51, 99, 0.5); + color: white; + } `; const BuildingDetail: React.FC = ({ building }) => { const [selectedFloor, setSelectedFloor] = useState(null); @@ -53,12 +127,26 @@ const BuildingDetail: React.FC = ({ building }) => { - {selectedFloor && ( - -

{selectedFloor} 정보

-

여기에 {selectedFloor}에 대한 정보를 추가하세요.

-
- )} + + {selectedFloor} 내부시설 + + + + + + + + 1층 화장실 + + 저장 + + 아직까지 작성된 리뷰가 없습니다! + + 좋아요 0개 + 싫어요 0개 + + + + ); }; diff --git a/src/components/FacilityDetail.tsx b/src/components/FacilityDetail.tsx new file mode 100644 index 0000000..14bc8cb --- /dev/null +++ b/src/components/FacilityDetail.tsx @@ -0,0 +1,9 @@ +const FacilityDetail: React.FC = () => { + return ( +
+

Facility Detail

+
+ ); +}; + +export default FacilityDetail; From ed73d4bf0f833517afa43a40337f2b63080d6965 Mon Sep 17 00:00:00 2001 From: leejuhi <163210518+leejuhi@users.noreply.github.com> Date: Wed, 15 Jan 2025 03:04:07 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=EB=94=94=ED=85=A1=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=84=98=EC=96=B4=EA=B0=80=EB=8A=94=EA=B1=B0=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 함수구현 --- src/components/Building.tsx | 2 +- src/components/BuildingDetail.tsx | 121 ++++++++++++++++------------ src/components/FacilityDetail.tsx | 26 +++++- src/components/HomeBoard.tsx | 109 ++++++++++++++----------- src/components/data/buildingData.ts | 17 +++- 5 files changed, 165 insertions(+), 110 deletions(-) diff --git a/src/components/Building.tsx b/src/components/Building.tsx index 2b5ce14..3cba1ee 100644 --- a/src/components/Building.tsx +++ b/src/components/Building.tsx @@ -22,6 +22,7 @@ const BuildingItem = styled.a` display: flex; margin: 20px 0px; color: black; + cursor: pointer; `; const Image = styled.img` width: 100px; @@ -54,7 +55,6 @@ const Building: React.FC = ({ onBuildingClick }) => { <> onBuildingClick(building)} > diff --git a/src/components/BuildingDetail.tsx b/src/components/BuildingDetail.tsx index 24cca2e..b574680 100644 --- a/src/components/BuildingDetail.tsx +++ b/src/components/BuildingDetail.tsx @@ -1,11 +1,75 @@ import styled from "@emotion/styled"; -import { BuildingInfo } from "./data/buildingData"; +import { BuildingInfo, FacilityInfo } from "./data/buildingData"; import Divider from "./Divider"; import { useState } from "react"; -const FacilityItems = styled.div` +interface BuildingDetailProps { + building: BuildingInfo; + onFacilityClick?: (facility: FacilityInfo) => void; +} +const BuildingDetail: React.FC = ({ + building, + onFacilityClick, +}) => { + const [selectedFloor, setSelectedFloor] = useState(null); + + const handleFloorChange = (event: React.ChangeEvent) => { + setSelectedFloor(event.target.value); + }; + return ( + <> + {building.name} + +

{building.name}

+

운영 시간: {building.time}

+ + + {building.floors.map((floor) => ( + + ))} + +
+ + + + {selectedFloor ? `${selectedFloor}층 내부 시설` : "내부 시설"} + + + + + + + {building.facilities?.map((facility) => ( + <> + onFacilityClick?.(facility)} + > + + {facility.name} + + 저장 + + 아직까지 작성된 리뷰가 없습니다! + + 좋아요 {facility.like}개 + 싫어요 {facility.dislike}개 + + + + + ))} + + + ); +}; + +export default BuildingDetail; +const FacilityItems = styled.a` display: flex; - padding: 20px 0px; + margin: 20px 0px; flex-direction: column; + cursor: pointer; `; const TitleItems = styled.div` display: flex; @@ -54,9 +118,7 @@ const Button = styled.button` background: rgb(0, 51, 99, 0.5); } `; -interface BuildingDetailProps { - building: BuildingInfo; -} + const Image = styled.img` width: 100%; height: 200px; @@ -105,50 +167,3 @@ const LikeButton = styled.button` color: white; } `; -const BuildingDetail: React.FC = ({ building }) => { - const [selectedFloor, setSelectedFloor] = useState(null); - - const handleFloorChange = (event: React.ChangeEvent) => { - setSelectedFloor(event.target.value); - }; - return ( - <> - {building.name} - -

{building.name}

-

운영 시간: {building.time}

- - - {building.floors.map((floor) => ( - - ))} - -
- - - {selectedFloor} 내부시설 - - - - - - - - 1층 화장실 - + 저장 - - 아직까지 작성된 리뷰가 없습니다! - - 좋아요 0개 - 싫어요 0개 - - - - - - ); -}; - -export default BuildingDetail; diff --git a/src/components/FacilityDetail.tsx b/src/components/FacilityDetail.tsx index 14bc8cb..5070b48 100644 --- a/src/components/FacilityDetail.tsx +++ b/src/components/FacilityDetail.tsx @@ -1,9 +1,27 @@ -const FacilityDetail: React.FC = () => { +import React from "react"; +import { FacilityInfo } from "./data/buildingData"; +import styled from "@emotion/styled"; + +interface FacilityDetailProps { + facility: FacilityInfo; +} + +const FacilityDetail: React.FC = ({ facility }) => { return ( -
-

Facility Detail

-
+ +

{facility.name}

+

층: {facility.floor}

+

좋아요: {facility.like}

+

싫어요: {facility.dislike}

+

리뷰 수: {facility.reviewCount}

+
); }; export default FacilityDetail; + +// styled-components 예시 +const Container = styled.div` + width: 400px; + padding: 20px; +`; diff --git a/src/components/HomeBoard.tsx b/src/components/HomeBoard.tsx index bdad230..a48a6a6 100644 --- a/src/components/HomeBoard.tsx +++ b/src/components/HomeBoard.tsx @@ -2,8 +2,67 @@ import styled from "@emotion/styled"; import { useState } from "react"; import { IoIosArrowBack, IoIosArrowForward } from "react-icons/io"; import Building from "./Building"; -import { BuildingInfo } from "./data/buildingData.ts"; +import { BuildingInfo, FacilityInfo } from "./data/buildingData.ts"; import BuildingDetail from "./BuildingDetail.tsx"; +import FacilityDetail from "./FacilityDetail.tsx"; + +const HomeBoard = () => { + const [isOpen, setIsOpen] = useState(false); + const [building, setBuilding] = useState(null); + const [facility, setFacility] = useState(null); + const toggleMenu = () => { + setIsOpen(!isOpen); + }; + const handleClick = (building: BuildingInfo) => { + setBuilding(building); + }; + const handleFacilityClick = (facility: FacilityInfo) => { + setFacility(facility); + }; + return ( + <> + + +
  • + 화장실 +
  • +
  • + 정수기 +
  • +
  • + 카페 +
  • +
    + + + {facility ? ( + + ) : building ? ( + + ) : ( + + )} + +
    + + ); +}; + +export default HomeBoard; + interface PanelProps { isOpen: boolean; } @@ -54,51 +113,3 @@ const Button = styled.button` cursor: pointer; font-size: 17px; `; - -const HomeBoard = () => { - const [isOpen, setIsOpen] = useState(false); - const [building, setBuilding] = useState(null); - const toggleMenu = () => { - setIsOpen(!isOpen); - }; - const handleClick = (building: BuildingInfo) => { - setBuilding(building); - }; - return ( - <> - - -
  • - 화장실 -
  • -
  • - 정수기 -
  • -
  • - 카페 -
  • -
    - - - {building ? ( - - ) : ( - - )} - -
    - - ); -}; - -export default HomeBoard; diff --git a/src/components/data/buildingData.ts b/src/components/data/buildingData.ts index 4649a3f..9a4b7d1 100644 --- a/src/components/data/buildingData.ts +++ b/src/components/data/buildingData.ts @@ -2,7 +2,15 @@ export interface BuildingInfo { image: string; name: string; time: string; - floors: string[]; + floors: number[]; + facilities?: FacilityInfo[]; +} +export interface FacilityInfo { + floor: string; + name: string; + like: number; + dislike: number; + reviewCount: number; } export const buildingData: BuildingInfo[] = [ @@ -11,12 +19,15 @@ export const buildingData: BuildingInfo[] = [ "https://photo.hongik.ac.kr/app/board/attach/image/thumb_353_1697760691000.do", name: "홍문관", time: "10:00~18:00", - floors: ["1층", "2층", "3층", "4층", "5층", "6층", "7층", "8층"], + floors: [1, 2, 3, 4, 5, 6, 7, 8], + facilities: [ + { floor: "1", name: "화장실", like: 0, dislike: 0, reviewCount: 0 }, + ], }, { image: "https://www.hongik.ac.kr/front/images/local/common/logo.png", name: "와우관", time: "00:00~24:00", - floors: ["1층", "2층", "3층", "4층", "5층", "6층", "7층", "8층"], + floors: [1, 2, 3, 4, 5, 6, 7, 8], }, ]; From acf0c381317f01643a3ab1b883349ee851c8d1e7 Mon Sep 17 00:00:00 2001 From: leejuhi <163210518+leejuhi@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:59:16 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=EB=A7=88=EC=BB=A4=20Click=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Click event --- src/components/Building.tsx | 67 +++++++-------- src/components/BuildingDetail.tsx | 17 +--- src/components/FacilityDetail.tsx | 121 +++++++++++++++++++++++++--- src/components/HomeBoard.tsx | 30 ++++--- src/components/LikeButton.tsx | 20 +++++ src/components/data/buildingData.ts | 37 ++++++++- src/components/map/Kakaomap.tsx | 59 +++++++++++++- src/components/pages/Homepage.tsx | 22 ++++- 8 files changed, 294 insertions(+), 79 deletions(-) create mode 100644 src/components/LikeButton.tsx diff --git a/src/components/Building.tsx b/src/components/Building.tsx index 3cba1ee..b6f3159 100644 --- a/src/components/Building.tsx +++ b/src/components/Building.tsx @@ -1,6 +1,40 @@ import styled from "@emotion/styled"; import Divider from "./Divider.tsx"; import { buildingData, BuildingInfo } from "./data/buildingData.ts"; + +interface BuildingProps { + onBuildingClick: (building: BuildingInfo) => void; +} +const Building: React.FC = ({ onBuildingClick }) => { + return ( + <> + + 홍익대학교 + + + + 내부건물 + {buildingData.map((building) => ( + <> + onBuildingClick(building)} + > + + + {building.name} +
    운영 시간: {building.time}
    +
    +
    + + + ))} +
    + + ); +}; +export default Building; + const Container = styled.div` width: 400px; position: relative; @@ -38,36 +72,3 @@ const Name = styled.div` font-size: 20px; font-weight: 500; `; - -interface BuildingProps { - onBuildingClick: (building: BuildingInfo) => void; -} -const Building: React.FC = ({ onBuildingClick }) => { - return ( - <> - - 홍익대학교 - - - - 내부건물 - {buildingData.map((building) => ( - <> - onBuildingClick(building)} - > - - - {building.name} -
    운영 시간: {building.time}
    -
    -
    - - - ))} -
    - - ); -}; -export default Building; diff --git a/src/components/BuildingDetail.tsx b/src/components/BuildingDetail.tsx index b574680..d06c5aa 100644 --- a/src/components/BuildingDetail.tsx +++ b/src/components/BuildingDetail.tsx @@ -2,6 +2,7 @@ import styled from "@emotion/styled"; import { BuildingInfo, FacilityInfo } from "./data/buildingData"; import Divider from "./Divider"; import { useState } from "react"; +import LikeButton from "./LikeButton"; interface BuildingDetailProps { building: BuildingInfo; onFacilityClick?: (facility: FacilityInfo) => void; @@ -151,19 +152,3 @@ const Like = styled.div` gap: 10px; margin: 15px 0px 10px 0px; `; - -const LikeButton = styled.button` - border: none; - background: rgb(0, 51, 99, 0.2); - color: black; - padding: 5px 10px; - border-radius: 10px; - font-size: 13px; - font-weight: 300; - cursor: pointer; - white-space: nowrap; - &:hover { - background: rgb(0, 51, 99, 0.5); - color: white; - } -`; diff --git a/src/components/FacilityDetail.tsx b/src/components/FacilityDetail.tsx index 5070b48..69b877f 100644 --- a/src/components/FacilityDetail.tsx +++ b/src/components/FacilityDetail.tsx @@ -1,6 +1,9 @@ import React from "react"; import { FacilityInfo } from "./data/buildingData"; import styled from "@emotion/styled"; +import LikeButton from "./LikeButton"; +import Divider from "./Divider"; +import { IoMdHeart } from "react-icons/io"; interface FacilityDetailProps { facility: FacilityInfo; @@ -8,20 +11,118 @@ interface FacilityDetailProps { const FacilityDetail: React.FC = ({ facility }) => { return ( - -

    {facility.name}

    -

    층: {facility.floor}

    -

    좋아요: {facility.like}

    -

    싫어요: {facility.dislike}

    -

    리뷰 수: {facility.reviewCount}

    -
    + <> + + + <h2> + {facility.floor}층 {facility.name} + </h2> + <Building>{facility.building} </Building> + + + 좋아요 {facility.like}개 + 싫어요 {facility.dislike}개 + + + + + +

    리뷰 {facility.reviewCount}개

    +
    + + + 등록 + + + {facility.review.map((review) => ( + <> + + + +
    {review.contents}
    + + + {review.like} + +
    +
    +
    + {review.user} +
    +
    + {review.date} +
    +
    +
    + + ))} +
    + ); }; export default FacilityDetail; - -// styled-components 예시 +const ReviewContainer = styled.div` + padding: 0px 10px; + margin-bottom: 10px; +`; const Container = styled.div` width: 400px; - padding: 20px; + padding: 20px 30px; +`; +const Title = styled.div` + display: flex; + align-items: center; + margin-top: 10px; +`; +const Building = styled.p` + margin-left: 10px; + color: #a7a7a7; +`; +const Like = styled.div` + display: flex; + gap: 10px; + margin: 15px 0px 10px 0px; +`; +const Review = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-top: 10px; + margin-bottom: 5px; + font-weight: 300; +`; +const Input = styled.input` + width: 83%; + height: 35px; + border: none; + background: #f2f2f2; + border-radius: 5px; + padding: 0px 10px; +`; +const ReviewButton = styled.button` + border: none; + width: 15%; + border-radius: 5px; + background: #8099b1; + color: white; + &:hover { + background: #003363; + } +`; +const ReviewInput = styled.div` + display: flex; + justify-content: space-between; + margin-bottom: 25px; + margin-top: 20px; `; diff --git a/src/components/HomeBoard.tsx b/src/components/HomeBoard.tsx index a48a6a6..254149d 100644 --- a/src/components/HomeBoard.tsx +++ b/src/components/HomeBoard.tsx @@ -6,22 +6,28 @@ import { BuildingInfo, FacilityInfo } from "./data/buildingData.ts"; import BuildingDetail from "./BuildingDetail.tsx"; import FacilityDetail from "./FacilityDetail.tsx"; -const HomeBoard = () => { - const [isOpen, setIsOpen] = useState(false); - const [building, setBuilding] = useState(null); +interface HomeBoardProps { + onBuildingClick: (building: BuildingInfo) => void; + selectedBuilding: BuildingInfo | null; + isPanelOpen: boolean; + setIsPanelOpen: (isPanelOpen: boolean) => void; +} +const HomeBoard: React.FC = ({ + selectedBuilding, + onBuildingClick, + isPanelOpen, + setIsPanelOpen, +}) => { const [facility, setFacility] = useState(null); const toggleMenu = () => { - setIsOpen(!isOpen); - }; - const handleClick = (building: BuildingInfo) => { - setBuilding(building); + setIsPanelOpen(!isPanelOpen); }; const handleFacilityClick = (facility: FacilityInfo) => { setFacility(facility); }; return ( <> - +
  • 화장실 @@ -34,7 +40,7 @@ const HomeBoard = () => {
  • - - + + + {building.facilities?.map((facility) => ( <> @@ -47,17 +70,45 @@ const BuildingDetail: React.FC = ({ key={facility.name} onClick={() => onFacilityClick?.(facility)} > - - {facility.name} - + 저장 - - 아직까지 작성된 리뷰가 없습니다! - - 좋아요 {facility.like}개 - 싫어요 {facility.dislike}개 - + {selectedFloor ? ( + <> + {selectedFloor === facility.floor && ( + <> + {selectedType ? ( + facility.type === selectedType && ( + <> + + + + ) + ) : ( + <> + + + + )} + + )} + + ) : ( + <> + {" "} + {selectedType ? ( + facility.type === selectedType && ( + <> + + + + ) + ) : ( + <> + + + + )} + + )} - ))} @@ -72,28 +123,7 @@ const FacilityItems = styled.a` flex-direction: column; cursor: pointer; `; -const TitleItems = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; -`; -const StoreButton = styled.button` - border: none; - background: #8099b1; - color: white; - padding: 2px; - width: 50px; - height: 27px; - border-radius: 10px; - font-size: 13px; - font-weight: 300; - cursor: pointer; - white-space: nowrap; - &:hover { - background: rgb(0, 51, 99, 0.8); - } -`; + const Facilities = styled.div` display: flex; gap: 10px; @@ -103,7 +133,10 @@ const DetailTitle = styled.p` font-weight: 500; margin: 10px 0px; `; -const Button = styled.button` +interface ButtonProps { + selected: boolean; +} +const Button = styled.button` border: none; background: #a7a7a7; color: white; @@ -118,6 +151,11 @@ const Button = styled.button` &:hover { background: rgb(0, 51, 99, 0.5); } + ${({ selected }) => + selected && + ` + background: rgb(0, 51, 99, 0.5); + `}// `; const Image = styled.img` @@ -142,13 +180,3 @@ const DropDown = styled.select` color: white; appearance: none; `; -const Review = styled.div` - font-size: 15px; - font-weight: 300; - color: #a7a7a7; -`; -const Like = styled.div` - display: flex; - gap: 10px; - margin: 15px 0px 10px 0px; -`; diff --git a/src/components/FacilityItem.tsx b/src/components/FacilityItem.tsx new file mode 100644 index 0000000..c5544ce --- /dev/null +++ b/src/components/FacilityItem.tsx @@ -0,0 +1,71 @@ +import styled from "@emotion/styled"; +import LikeButton from "./LikeButton.tsx"; +import { FacilityInfo } from "./data/buildingData.ts"; +interface FacilityItemProps { + facility?: FacilityInfo | null; +} +const FacilityItem: React.FC = ({ facility }) => { + return ( + <> + {facility ? ( + <> + + + {facility.floor}층 {facility.name} + + + 저장 + + 아직까지 작성된 리뷰가 없습니다! + + 좋아요 {facility.like}개 + 싫어요 {facility.dislike}개 + + + ) : ( +

    시설 정보가 없습니다.

    + )} + + ); +}; + +export default FacilityItem; + +const TitleItems = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +`; +const StoreButton = styled.button` + border: none; + background: #8099b1; + color: white; + padding: 2px; + width: 50px; + height: 27px; + border-radius: 10px; + font-size: 13px; + font-weight: 300; + cursor: pointer; + white-space: nowrap; + &:hover { + background: rgb(0, 51, 99, 0.8); + } +`; + +const DetailTitle = styled.p` + font-size: 20px; + font-weight: 500; + margin: 10px 0px; +`; + +const Review = styled.div` + font-size: 15px; + font-weight: 300; + color: #a7a7a7; +`; +const Like = styled.div` + display: flex; + gap: 10px; + margin: 15px 0px 10px 0px; +`; diff --git a/src/components/data/buildingData.ts b/src/components/data/buildingData.ts index a202cb6..cfed75f 100644 --- a/src/components/data/buildingData.ts +++ b/src/components/data/buildingData.ts @@ -8,6 +8,7 @@ export interface BuildingInfo { } export interface FacilityInfo { building: string; + type: number; floor: string; name: string; like: number; @@ -33,6 +34,7 @@ export const buildingData: BuildingInfo[] = [ { building: "홍문관", floor: "1", + type: 1, name: "화장실", like: 0, dislike: 0, @@ -55,10 +57,36 @@ export const buildingData: BuildingInfo[] = [ ], }, { - image: "https://www.hongik.ac.kr/front/images/local/common/logo.png", + image: + "https://photo.hongik.ac.kr/app/board/attach/image/thumb_732_1700796628000.do", name: "와우관", time: "00:00~24:00", coordinates: { lat: 37.55167104651813, lng: 126.926557030475 }, floors: [1, 2, 3, 4, 5, 6, 7, 8], + facilities: [ + { + building: "와우관", + floor: "3", + type: 1, + name: "화장실", + like: 3, + dislike: 0, + reviewCount: 2, + review: [ + { + contents: "안녕하세요", + user: "컴공생", + date: "2021.09.01", + like: 0, + }, + { + contents: "깨끗해요!", + user: "자율전공샹", + date: "2025.10.01", + like: 3, + }, + ], + }, + ], }, ]; From ba5fd7dc5b014f9a8029144d15c2071102cb4697 Mon Sep 17 00:00:00 2001 From: leejuhi <163210518+leejuhi@users.noreply.github.com> Date: Fri, 17 Jan 2025 02:50:36 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20=EB=A7=88=EC=BB=A4=20=EB=8B=A4=20?= =?UTF-8?q?=EB=9C=A8=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 수정 --- src/components/Building.tsx | 50 ++++----- src/components/BuildingDetail.tsx | 159 ++++++++++++++-------------- src/components/Divider.tsx | 1 + src/components/Overflow.tsx | 9 ++ src/components/data/buildingData.ts | 40 +++++++ src/components/map/Kakaomap.tsx | 18 +--- 6 files changed, 161 insertions(+), 116 deletions(-) create mode 100644 src/components/Overflow.tsx diff --git a/src/components/Building.tsx b/src/components/Building.tsx index b6f3159..bd1f1ee 100644 --- a/src/components/Building.tsx +++ b/src/components/Building.tsx @@ -1,6 +1,7 @@ import styled from "@emotion/styled"; import Divider from "./Divider.tsx"; import { buildingData, BuildingInfo } from "./data/buildingData.ts"; +import Overflow from "./Overflow.tsx"; interface BuildingProps { onBuildingClick: (building: BuildingInfo) => void; @@ -8,28 +9,30 @@ interface BuildingProps { const Building: React.FC = ({ onBuildingClick }) => { return ( <> - - 홍익대학교 - - - - 내부건물 - {buildingData.map((building) => ( - <> - onBuildingClick(building)} - > - - - {building.name} -
    운영 시간: {building.time}
    -
    -
    - - - ))} -
    + + + 홍익대학교 + + + + 내부건물 + {buildingData.map((building) => ( + <> + onBuildingClick(building)} + > + + + {building.name} +
    운영 시간: {building.time}
    +
    +
    + + + ))} +
    +
    ); }; @@ -39,7 +42,6 @@ const Container = styled.div` width: 400px; position: relative; padding: 20px 30px; - overflow: hidden; `; const Title = styled.div` margin: 10px 0px; @@ -50,7 +52,7 @@ const Title = styled.div` const SubTitle = styled.div` font-size: 25px; font-weight: 500; - margin: 10px 0px; + margin-bottom: 10px; `; const BuildingItem = styled.a` display: flex; diff --git a/src/components/BuildingDetail.tsx b/src/components/BuildingDetail.tsx index dd1b801..6242d2f 100644 --- a/src/components/BuildingDetail.tsx +++ b/src/components/BuildingDetail.tsx @@ -3,6 +3,7 @@ import { BuildingInfo, FacilityInfo } from "./data/buildingData"; import Divider from "./Divider"; import { useState } from "react"; import FacilityItem from "./FacilityItem.tsx"; +import Overflow from "./Overflow.tsx"; interface BuildingDetailProps { building: BuildingInfo; onFacilityClick?: (facility: FacilityInfo) => void; @@ -24,102 +25,105 @@ const BuildingDetail: React.FC = ({ }; return ( <> - {building.name} - -

    {building.name}

    -

    운영 시간: {building.time}

    - - - {building.floors.map((floor) => ( - +
    + + + + {selectedFloor ? `${selectedFloor}층 내부 시설` : "내부 시설"} + + + + + + + + {building.facilities?.map((facility) => ( + <> + onFacilityClick?.(facility)} + > + {selectedFloor ? ( + <> + {selectedFloor === facility.floor && ( + <> + {selectedType ? ( + facility.type === selectedType && ( + <> + + + + ) + ) : ( <> - ) - ) : ( + )} + + )} + + ) : ( + <> + {" "} + {selectedType ? ( + facility.type === selectedType && ( <> - )} - - )} - - ) : ( - <> - {" "} - {selectedType ? ( - facility.type === selectedType && ( + ) + ) : ( <> - ) - ) : ( - <> - - - - )} - - )} - - - ))} - + )} + + )} + + + ))} + + ); }; export default BuildingDetail; + const FacilityItems = styled.a` display: flex; - margin: 20px 0px; flex-direction: column; cursor: pointer; `; @@ -127,11 +131,12 @@ const FacilityItems = styled.a` const Facilities = styled.div` display: flex; gap: 10px; + margin-bottom: 20px; `; const DetailTitle = styled.p` font-size: 20px; font-weight: 500; - margin: 10px 0px; + margin-bottom: 10px; `; interface ButtonProps { selected: boolean; @@ -142,7 +147,7 @@ const Button = styled.button` color: white; padding: 5px 10px; border-radius: 10px; - font-size: 18px; + font-size: 17px; font-weight: 300; width: 84px; cursor: pointer; diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx index 8be5d48..5ee4db2 100644 --- a/src/components/Divider.tsx +++ b/src/components/Divider.tsx @@ -6,6 +6,7 @@ const Divider = styled.div` width: 100%; height: ${({ size }) => (size ? "10px" : "1px")}; background: #e9e9e9; + margin-bottom: 10px; `; export default Divider; diff --git a/src/components/Overflow.tsx b/src/components/Overflow.tsx new file mode 100644 index 0000000..dc4b263 --- /dev/null +++ b/src/components/Overflow.tsx @@ -0,0 +1,9 @@ +import styled from "@emotion/styled"; + +const Overflow = styled.div` + overflow-y: auto; + height: 100vh; + overflow-x: hidden; +`; + +export default Overflow; diff --git a/src/components/data/buildingData.ts b/src/components/data/buildingData.ts index cfed75f..6c687f2 100644 --- a/src/components/data/buildingData.ts +++ b/src/components/data/buildingData.ts @@ -54,6 +54,46 @@ export const buildingData: BuildingInfo[] = [ }, ], }, + { + building: "홍문관", + floor: "3", + type: 1, + name: "화장실", + like: 0, + dislike: 0, + reviewCount: 2, + review: [ + { + contents: "안녕하세요", + user: "컴공생", + date: "2021.09.01", + like: 0, + }, + { + contents: "깨끗해요!", + user: "자율전공샹", + date: "2025.10.01", + like: 3, + }, + ], + }, + { + building: "홍문관", + floor: "1", + type: 3, + name: "카페나무", + like: 4, + dislike: 2, + reviewCount: 1, + review: [ + { + contents: "안녕하세요", + user: "컴공생", + date: "2021.09.01", + like: 0, + }, + ], + }, ], }, { diff --git a/src/components/map/Kakaomap.tsx b/src/components/map/Kakaomap.tsx index 24355c0..16d0633 100644 --- a/src/components/map/Kakaomap.tsx +++ b/src/components/map/Kakaomap.tsx @@ -17,8 +17,8 @@ const Kakaomap: React.FC = ({ selectedBuilding, onBuildingClick, }) => { - const addMarkers = (map: any, selectedBuilding: BuildingInfo | null) => { - if (!selectedBuilding) { + const addMarkers = (map: any) => { + { buildingData.forEach((building) => { const markerPosition = new kakao.maps.LatLng( building.coordinates.lat, @@ -32,18 +32,6 @@ const Kakaomap: React.FC = ({ onBuildingClick(building); }); }); - } else { - const markerPosition = new kakao.maps.LatLng( - selectedBuilding.coordinates.lat, - selectedBuilding.coordinates.lng - ); - const marker = new kakao.maps.Marker({ - position: markerPosition, - }); - marker.setMap(map); - kakao.maps.event.addListener(marker, "click", () => { - onBuildingClick(selectedBuilding); - }); } }; @@ -54,7 +42,7 @@ const Kakaomap: React.FC = ({ level: 1, }; const map = new kakao.maps.Map(container, options); - addMarkers(map, selectedBuilding); + addMarkers(map); // 선택된 건물이 변경될 때 지도를 해당 위치로 이동 if (selectedBuilding) {