From 11c93edff43c7c7a248234cd4f2993019806a04c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:53:02 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=EB=B9=8C=EB=A6=B4=EA=B2=8C=20?= =?UTF-8?q?=EB=AC=BC=ED=92=88=20=EB=B0=8F=20Bottom=20Nav=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20asset=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Figma에서 물품 아이콘 16종, Bottom Nav 선택 상태 아이콘 4종, 스테퍼 아이콘 2종을 내려받아 추가한다 --- .../icons/bottom-nav/board-selected.svg | 12 ++++++++ .../icons/bottom-nav/event-selected.svg | 5 ++++ src/assets/icons/bottom-nav/home-selected.svg | 5 ++++ .../icons/bottom-nav/rental-selected.svg | 16 ++++++++++ src/assets/icons/circle-minus-fill.svg | 5 ++++ src/assets/icons/circle-plus-fill.svg | 5 ++++ .../icons/rental-items/8pin-charger.svg | 30 +++++++++++++++++++ .../icons/rental-items/alcohol-swab.svg | 24 +++++++++++++++ src/assets/icons/rental-items/band-aid.svg | 20 +++++++++++++ .../icons/rental-items/curling-iron.svg | 22 ++++++++++++++ src/assets/icons/rental-items/default.svg | 14 +++++++++ src/assets/icons/rental-items/eye-drops.svg | 21 +++++++++++++ src/assets/icons/rental-items/hair-dryer.svg | 21 +++++++++++++ .../icons/rental-items/laptop-charger.svg | 22 ++++++++++++++ src/assets/icons/rental-items/mask.svg | 23 ++++++++++++++ src/assets/icons/rental-items/ointment.svg | 21 +++++++++++++ .../icons/rental-items/pain-relief-patch.svg | 25 ++++++++++++++++ src/assets/icons/rental-items/pill.svg | 21 +++++++++++++ src/assets/icons/rental-items/power-bank.svg | 21 +++++++++++++ .../icons/rental-items/sanitary-pad.svg | 21 +++++++++++++ src/assets/icons/rental-items/umbrella.svg | 22 ++++++++++++++ .../icons/rental-items/usb-c-charger.svg | 23 ++++++++++++++ 22 files changed, 399 insertions(+) create mode 100644 src/assets/icons/bottom-nav/board-selected.svg create mode 100644 src/assets/icons/bottom-nav/event-selected.svg create mode 100644 src/assets/icons/bottom-nav/home-selected.svg create mode 100644 src/assets/icons/bottom-nav/rental-selected.svg create mode 100644 src/assets/icons/circle-minus-fill.svg create mode 100644 src/assets/icons/circle-plus-fill.svg create mode 100644 src/assets/icons/rental-items/8pin-charger.svg create mode 100644 src/assets/icons/rental-items/alcohol-swab.svg create mode 100644 src/assets/icons/rental-items/band-aid.svg create mode 100644 src/assets/icons/rental-items/curling-iron.svg create mode 100644 src/assets/icons/rental-items/default.svg create mode 100644 src/assets/icons/rental-items/eye-drops.svg create mode 100644 src/assets/icons/rental-items/hair-dryer.svg create mode 100644 src/assets/icons/rental-items/laptop-charger.svg create mode 100644 src/assets/icons/rental-items/mask.svg create mode 100644 src/assets/icons/rental-items/ointment.svg create mode 100644 src/assets/icons/rental-items/pain-relief-patch.svg create mode 100644 src/assets/icons/rental-items/pill.svg create mode 100644 src/assets/icons/rental-items/power-bank.svg create mode 100644 src/assets/icons/rental-items/sanitary-pad.svg create mode 100644 src/assets/icons/rental-items/umbrella.svg create mode 100644 src/assets/icons/rental-items/usb-c-charger.svg diff --git a/src/assets/icons/bottom-nav/board-selected.svg b/src/assets/icons/bottom-nav/board-selected.svg new file mode 100644 index 0000000..2e82950 --- /dev/null +++ b/src/assets/icons/bottom-nav/board-selected.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/bottom-nav/event-selected.svg b/src/assets/icons/bottom-nav/event-selected.svg new file mode 100644 index 0000000..6648b26 --- /dev/null +++ b/src/assets/icons/bottom-nav/event-selected.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/bottom-nav/home-selected.svg b/src/assets/icons/bottom-nav/home-selected.svg new file mode 100644 index 0000000..e9e47dc --- /dev/null +++ b/src/assets/icons/bottom-nav/home-selected.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/bottom-nav/rental-selected.svg b/src/assets/icons/bottom-nav/rental-selected.svg new file mode 100644 index 0000000..cb2392d --- /dev/null +++ b/src/assets/icons/bottom-nav/rental-selected.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/circle-minus-fill.svg b/src/assets/icons/circle-minus-fill.svg new file mode 100644 index 0000000..ad62883 --- /dev/null +++ b/src/assets/icons/circle-minus-fill.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/circle-plus-fill.svg b/src/assets/icons/circle-plus-fill.svg new file mode 100644 index 0000000..b00fa3a --- /dev/null +++ b/src/assets/icons/circle-plus-fill.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/rental-items/8pin-charger.svg b/src/assets/icons/rental-items/8pin-charger.svg new file mode 100644 index 0000000..481c548 --- /dev/null +++ b/src/assets/icons/rental-items/8pin-charger.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/alcohol-swab.svg b/src/assets/icons/rental-items/alcohol-swab.svg new file mode 100644 index 0000000..ec57d64 --- /dev/null +++ b/src/assets/icons/rental-items/alcohol-swab.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/band-aid.svg b/src/assets/icons/rental-items/band-aid.svg new file mode 100644 index 0000000..5456739 --- /dev/null +++ b/src/assets/icons/rental-items/band-aid.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/curling-iron.svg b/src/assets/icons/rental-items/curling-iron.svg new file mode 100644 index 0000000..a13d2e6 --- /dev/null +++ b/src/assets/icons/rental-items/curling-iron.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/default.svg b/src/assets/icons/rental-items/default.svg new file mode 100644 index 0000000..8cae4eb --- /dev/null +++ b/src/assets/icons/rental-items/default.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/eye-drops.svg b/src/assets/icons/rental-items/eye-drops.svg new file mode 100644 index 0000000..5a82cbd --- /dev/null +++ b/src/assets/icons/rental-items/eye-drops.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/hair-dryer.svg b/src/assets/icons/rental-items/hair-dryer.svg new file mode 100644 index 0000000..6578d26 --- /dev/null +++ b/src/assets/icons/rental-items/hair-dryer.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/laptop-charger.svg b/src/assets/icons/rental-items/laptop-charger.svg new file mode 100644 index 0000000..20df526 --- /dev/null +++ b/src/assets/icons/rental-items/laptop-charger.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/mask.svg b/src/assets/icons/rental-items/mask.svg new file mode 100644 index 0000000..b1c90a6 --- /dev/null +++ b/src/assets/icons/rental-items/mask.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/ointment.svg b/src/assets/icons/rental-items/ointment.svg new file mode 100644 index 0000000..2820271 --- /dev/null +++ b/src/assets/icons/rental-items/ointment.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/pain-relief-patch.svg b/src/assets/icons/rental-items/pain-relief-patch.svg new file mode 100644 index 0000000..decb03d --- /dev/null +++ b/src/assets/icons/rental-items/pain-relief-patch.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/pill.svg b/src/assets/icons/rental-items/pill.svg new file mode 100644 index 0000000..f399c53 --- /dev/null +++ b/src/assets/icons/rental-items/pill.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/power-bank.svg b/src/assets/icons/rental-items/power-bank.svg new file mode 100644 index 0000000..d2c4340 --- /dev/null +++ b/src/assets/icons/rental-items/power-bank.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/sanitary-pad.svg b/src/assets/icons/rental-items/sanitary-pad.svg new file mode 100644 index 0000000..69382ab --- /dev/null +++ b/src/assets/icons/rental-items/sanitary-pad.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/umbrella.svg b/src/assets/icons/rental-items/umbrella.svg new file mode 100644 index 0000000..fbd0e6a --- /dev/null +++ b/src/assets/icons/rental-items/umbrella.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/usb-c-charger.svg b/src/assets/icons/rental-items/usb-c-charger.svg new file mode 100644 index 0000000..b8ec969 --- /dev/null +++ b/src/assets/icons/rental-items/usb-c-charger.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + From 6f5f829ca6f1a27bc5b70a15d5248602feaae194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:53:10 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20RentalItemCard,=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=ED=95=84=ED=84=B0=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B0=8F=20=EB=AC=BC=ED=92=88=20?= =?UTF-8?q?=EB=AA=A9=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WDS Button(size=small)에 색상만 보정한 대여 신청 버튼 포함 RentalItemCard, Stream 로컬 카테고리 필터 칩, Figma Item Grid 기준 물품 19종 목데이터를 추가한다 --- .../components/RentalCategoryFilter.tsx | 40 +++++++++ .../rental/components/RentalItemCard.tsx | 90 +++++++++++++++++++ src/features/rental/constants/rentalItems.ts | 75 ++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/features/rental/components/RentalCategoryFilter.tsx create mode 100644 src/features/rental/components/RentalItemCard.tsx create mode 100644 src/features/rental/constants/rentalItems.ts diff --git a/src/features/rental/components/RentalCategoryFilter.tsx b/src/features/rental/components/RentalCategoryFilter.tsx new file mode 100644 index 0000000..d34d04b --- /dev/null +++ b/src/features/rental/components/RentalCategoryFilter.tsx @@ -0,0 +1,40 @@ +const RENTAL_CATEGORIES = [ + "전체", + "전자기기", + "생활잡화", + "상비약", + "위생용품", +]; + +interface RentalCategoryFilterProps { + value: string; + onChange: (category: string) => void; +} + +// Figma: 빌릴게 Filter Row (nodeId 1243:73337) — WDS Chip이 아니라 Stream 로컬 커스텀 칩. +// 카테고리·물품 매핑 API가 아직 없어 필터링 없이 선택 상태만 표시한다. +function RentalCategoryFilter({ value, onChange }: RentalCategoryFilterProps) { + return ( +
+ {RENTAL_CATEGORIES.map((category) => { + const active = category === value; + return ( + + ); + })} +
+ ); +} + +export default RentalCategoryFilter; diff --git a/src/features/rental/components/RentalItemCard.tsx b/src/features/rental/components/RentalItemCard.tsx new file mode 100644 index 0000000..3e8a65b --- /dev/null +++ b/src/features/rental/components/RentalItemCard.tsx @@ -0,0 +1,90 @@ +// Figma: Rental Item Card (nodeId 1041:61407) +import { Button } from "@wanteddev/wds"; + +import circleMinusFill from "@/assets/icons/circle-minus-fill.svg"; +import circlePlusFill from "@/assets/icons/circle-plus-fill.svg"; + +interface RentalItemCardProps { + icon: string; + itemName: string; + quantity: number; + trailingControl?: "button" | "stepper"; + onRentRequest?: () => void; + stepperValue?: number; + onStepperDecrease?: () => void; + onStepperIncrease?: () => void; +} + +// "대여 신청" 버튼은 Figma상 `Menu/Resource/Action Area/Trailing Content/Button`(WDS) 인스턴스지만, +// 그 이름과 1:1 대응하는 코드 export는 없다 — 대신 WDS `Button`(size="small")이 padding(7px/14px)· +// radius(8px)·타이포(label2)까지 정확히 일치해서 그걸 쓰고, Button 공개 variant엔 없는 "연한 파랑 배경 +// + 파랑 텍스트" 조합만 sx로 보정했다. 스테퍼 +/- 아이콘은 여전히 WDS 미확정이라 하드코딩 — docs/plans 참고. +function RentalItemCard({ + icon, + itemName, + quantity, + trailingControl = "button", + onRentRequest, + stepperValue = 1, + onStepperDecrease, + onStepperIncrease, +}: RentalItemCardProps) { + const isStepper = trailingControl === "stepper"; + + return ( +
+
+
+ +
+

+ {itemName} +

+

수량 {quantity}

+
+
+ + {!isStepper && ( + + )} + + {isStepper && ( +
+ + + {stepperValue} + + +
+ )} +
+
+ ); +} + +export default RentalItemCard; diff --git a/src/features/rental/constants/rentalItems.ts b/src/features/rental/constants/rentalItems.ts new file mode 100644 index 0000000..c3680f9 --- /dev/null +++ b/src/features/rental/constants/rentalItems.ts @@ -0,0 +1,75 @@ +import eightPinCharger from "@/assets/icons/rental-items/8pin-charger.svg"; +import alcoholSwab from "@/assets/icons/rental-items/alcohol-swab.svg"; +import bandAid from "@/assets/icons/rental-items/band-aid.svg"; +import curlingIron from "@/assets/icons/rental-items/curling-iron.svg"; +import eyeDrops from "@/assets/icons/rental-items/eye-drops.svg"; +import hairDryer from "@/assets/icons/rental-items/hair-dryer.svg"; +import laptopCharger from "@/assets/icons/rental-items/laptop-charger.svg"; +import mask from "@/assets/icons/rental-items/mask.svg"; +import ointment from "@/assets/icons/rental-items/ointment.svg"; +import painReliefPatch from "@/assets/icons/rental-items/pain-relief-patch.svg"; +import pill from "@/assets/icons/rental-items/pill.svg"; +import powerBank from "@/assets/icons/rental-items/power-bank.svg"; +import sanitaryPad from "@/assets/icons/rental-items/sanitary-pad.svg"; +import umbrella from "@/assets/icons/rental-items/umbrella.svg"; +import usbCCharger from "@/assets/icons/rental-items/usb-c-charger.svg"; + +export interface RentalItem { + id: string; + name: string; + quantity: number; + icon: string; +} + +// Figma: 빌릴게 Item Grid (nodeId 1243:73343) 순서·물품명·수량을 그대로 옮긴 목데이터 — 실 API 연동 전까지 사용 +export const RENTAL_ITEMS: RentalItem[] = [ + { icon: curlingIron, id: "curling-iron", name: "고데기", quantity: 28 }, + { + icon: laptopCharger, + id: "laptop-charger", + name: "노트북 충전기(C타입)", + quantity: 28, + }, + { icon: hairDryer, id: "hair-dryer", name: "드라이기", quantity: 28 }, + { icon: mask, id: "mask", name: "마스크", quantity: 28 }, + { icon: bandAid, id: "band-aid", name: "밴드", quantity: 28 }, + { icon: powerBank, id: "power-bank", name: "보조배터리", quantity: 28 }, + { + icon: sanitaryPad, + id: "sanitary-pad-large", + name: "생리대(대형)", + quantity: 28, + }, + { + icon: sanitaryPad, + id: "sanitary-pad-small", + name: "생리대(소형)", + quantity: 28, + }, + { icon: alcoholSwab, id: "alcohol-swab", name: "알콜스왑", quantity: 28 }, + { icon: umbrella, id: "umbrella", name: "우산", quantity: 28 }, + { icon: pill, id: "stomach-medicine", name: "위장약", quantity: 28 }, + { icon: pill, id: "easyen-6", name: "이지엔6", quantity: 28 }, + { icon: eyeDrops, id: "eye-drops", name: "인공눈물", quantity: 28 }, + { icon: pill, id: "cold-medicine", name: "종합감기약", quantity: 28 }, + { + icon: usbCCharger, + id: "usb-c-cable", + name: "케이블(C to C)", + quantity: 28, + }, + { icon: pill, id: "tylenol", name: "타이레놀", quantity: 28 }, + { + icon: painReliefPatch, + id: "pain-relief-patch", + name: "파스", + quantity: 28, + }, + { icon: ointment, id: "ointment", name: "후시딘", quantity: 28 }, + { + icon: eightPinCharger, + id: "8pin-charger", + name: "8핀 충전기", + quantity: 28, + }, +]; From 44a4d6b6b047d54fbdfb8a735a9add13ec526b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:53:18 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20Bottom=20Nav=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WDS BottomNavigation은 iOS 반투명 배경과 body 스크롤 감지 로직이 내부 스크롤 레이아웃과 안 맞아서 대신 Stream 로컬 컴포넌트로 홈/행사/게시판/빌릴게 4탭을 구현한다 --- src/components/ui/BottomNav.tsx | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/components/ui/BottomNav.tsx diff --git a/src/components/ui/BottomNav.tsx b/src/components/ui/BottomNav.tsx new file mode 100644 index 0000000..8bfe241 --- /dev/null +++ b/src/components/ui/BottomNav.tsx @@ -0,0 +1,94 @@ +import { + IconHome, + IconList, + IconStorage, + IconTicket, +} from "@wanteddev/wds-icon"; + +import boardSelected from "@/assets/icons/bottom-nav/board-selected.svg"; +import eventSelected from "@/assets/icons/bottom-nav/event-selected.svg"; +import homeSelected from "@/assets/icons/bottom-nav/home-selected.svg"; +import rentalSelected from "@/assets/icons/bottom-nav/rental-selected.svg"; + +export type BottomNavValue = "home" | "event" | "board" | "rental"; + +interface BottomNavProps { + value: BottomNavValue; + onValueChange: (value: BottomNavValue) => void; +} + +interface BottomNavTab { + value: BottomNavValue; + label: string; + NormalIcon: typeof IconHome; + selectedIcon: string; +} + +// WDS에 선택 상태용 filled 아이콘이 없는 탭(게시판)이 있어, 4개 전부 Figma에서 내려받은 selected 아이콘으로 통일했다. +const TABS: BottomNavTab[] = [ + { + NormalIcon: IconHome, + label: "홈", + selectedIcon: homeSelected, + value: "home", + }, + { + NormalIcon: IconTicket, + label: "행사", + selectedIcon: eventSelected, + value: "event", + }, + { + NormalIcon: IconList, + label: "게시판", + selectedIcon: boardSelected, + value: "board", + }, + { + NormalIcon: IconStorage, + label: "빌릴게", + selectedIcon: rentalSelected, + value: "rental", + }, +]; + +// Figma: Bottom Nav (nodeId 985:39948, Selected=Home/Event/Board/Rental) — WDS `BottomNavigation`은 +// iOS 반투명 배경 + body 스크롤 기준 투명 전환 로직이 있어 우리 레이아웃(내부 스크롤)과 안 맞아서 쓰지 않고 +// Stream 로컬 컴포넌트로 새로 만들었다. +// 상단 border 색은 Figma 스펙(Background/Elevated/Alternative, #f7f7f8)이 바로 위 스크롤 영역 배경과 완전히 +// 같은 색이라 실제로는 안 보여서, 눈에 보이는 구분선이 되도록 Line/Solid/Neutral로 바꿨다. +function BottomNav({ value, onValueChange }: BottomNavProps) { + return ( +
+
+ {TABS.map(({ value: tabValue, label, NormalIcon, selectedIcon }) => { + const isSelected = tabValue === value; + return ( + + ); + })} +
+
+
+
+
+ ); +} + +export default BottomNav; From ae2e1237e93b247d444e8e2012e00bc1614ae8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 12:53:28 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EB=B9=8C=EB=A6=B4=EA=B2=8C=20?= =?UTF-8?q?=EB=8C=80=EC=97=AC=20=EB=AA=A9=EB=A1=9D=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=A1=B0=EB=A6=BD=20=EB=B0=8F=20=EC=83=89=EC=83=81=20=EB=94=94?= =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=ED=86=A0=ED=81=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Top Navigation·Bottom Nav 고정 + 내부 스크롤 레이아웃(375x812)으로 화면을 조립하고, WDS semantic 변수를 Tailwind 색상 토큰으로 별칭 연결해 하드코딩 hex 없이 쓰도록 한다. 라우팅이 없어 App.tsx가 임시로 이 화면을 직접 렌더링한다 --- src/app/App.tsx | 9 ++- src/features/rental/RentalListScreen.tsx | 82 ++++++++++++++++++++++++ src/index.css | 21 +++++- src/main.tsx | 1 - 4 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/features/rental/RentalListScreen.tsx diff --git a/src/app/App.tsx b/src/app/App.tsx index d347dd4..6b9a3d1 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,8 +1,11 @@ +import RentalListScreen from "@/features/rental/RentalListScreen"; + +// 라우팅 도입 전까지 임시로 이 화면만 렌더링한다. 데스크톱에서 보기 좋게 아이폰 화면 크기로 가운데 정렬만 해준다. function App() { return ( -
-

STREAM

-
+
+ +
); } diff --git a/src/features/rental/RentalListScreen.tsx b/src/features/rental/RentalListScreen.tsx new file mode 100644 index 0000000..e02b10e --- /dev/null +++ b/src/features/rental/RentalListScreen.tsx @@ -0,0 +1,82 @@ +import { + SegmentedControl, + SegmentedControlItem, + TopNavigation, + TopNavigationButton, +} from "@wanteddev/wds"; +import { IconBell, IconSearch } from "@wanteddev/wds-icon"; +import { useState } from "react"; + +import BottomNav, { type BottomNavValue } from "@/components/ui/BottomNav"; +import RentalCategoryFilter from "@/features/rental/components/RentalCategoryFilter"; +import RentalItemCard from "@/features/rental/components/RentalItemCard"; +import { RENTAL_ITEMS } from "@/features/rental/constants/rentalItems"; + +// Figma: 빌릴게 (nodeId 1243:73331) +function RentalListScreen() { + const [tab, setTab] = useState("rent"); + const [category, setCategory] = useState("전체"); + const [bottomNavValue, setBottomNavValue] = + useState("rental"); + + return ( +
+
+ {/* background 기본값(true)은 iOS 반투명 스타일이라 뒤 배경이 비쳐 보인다. Figma는 별도 배경 없이 화면 배경을 그대로 쓴다. */} + + + 대여 + 반납 + +
+ } + trailingContent={ + <> + + + + + + + + } + variant="display" + > + 빌릴게 + +
+ +
+
+ +
+ + {tab === "rent" ? ( +
+ {RENTAL_ITEMS.map((item) => ( + + ))} +
+ ) : ( +
+ 반납 화면은 아직 준비 중이에요 +
+ )} +
+ +
+ +
+
+ ); +} + +export default RentalListScreen; diff --git a/src/index.css b/src/index.css index a3e7293..509d881 100644 --- a/src/index.css +++ b/src/index.css @@ -1,5 +1,24 @@ @import "tailwindcss"; +@import "@wanteddev/wds/global.css" layer(base); @theme { - /* 디자인 시스템 토큰 자리 — 디자인이 정해지면 색상·타이포그래피·간격 등을 여기에 채운다 */ + /* WDS(@wanteddev/wds/global.css)의 semantic/atomic CSS 변수를 Tailwind 색상 토큰으로 별칭 연결. */ + /* 값을 새로 정의하지 않고 WDS 걸 그대로 참조하므로 다크 테마(html[data-theme=dark])도 자동 반영된다. */ + /* Figma get_variable_defs로 뽑은 실제 값과 대조해서 확정함(빌릴게 화면, nodeId 1243:73331 기준). */ + --color-label-strong: var(--semantic-label-strong); + --color-label-normal: var(--semantic-label-normal); + --color-label-alternative: var(--semantic-label-alternative); + --color-label-assistive: var(--semantic-label-assistive); + + --color-background-normal: var(--semantic-background-normal-normal); + --color-background-alternative: var(--semantic-background-normal-alternative); + + --color-line-solid-neutral: var(--semantic-line-solid-neutral); + --color-line-normal-neutral: var(--semantic-line-normal-neutral); + + --color-primary: var(--semantic-primary-normal); + --color-primary-subtle: var(--atomic-blue-95); + + /* WDS 시맨틱 세트에 없는 값(Figma "Icons/Primary") — 홈 인디케이터 전용, 값 자체는 Figma에서 확인됨 */ + --color-icons-primary: #0f172a; } diff --git a/src/main.tsx b/src/main.tsx index c19e66d..cd7e812 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,7 +3,6 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./app/App.tsx"; import "./index.css"; -import "@wanteddev/wds/global.css"; createRoot(document.getElementById("root")!).render( From 89418061270cc02d1268c577900ba6456bbc531f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:04:06 +0900 Subject: [PATCH 5/7] =?UTF-8?q?fix:=20PR=20=EB=B2=94=EC=9C=84=EB=A5=BC=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83(375x8?= =?UTF-8?q?12)+Bottom=20Nav=EB=A1=9C=20=EC=A2=81=ED=9E=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 행사 등 다른 화면과 대조해보니 375x812 프레임 비율과 Bottom Nav 외에는 Top Navigation 구성·필터·리스트 등이 화면마다 달라 공통 레이아웃이 아니었다. 빌릴게 전용 컴포넌트(RentalItemCard, RentalCategoryFilter, 목데이터, 물품 아이콘)는 이 브랜치에서 빼고, header/children 슬롯만 받는 ScreenLayout으로 공통 뼈대만 남긴다. 빌릴게 화면 전용 작업은 별도 이슈로 다시 진행한다 --- src/app/App.tsx | 24 ++++- src/assets/icons/circle-minus-fill.svg | 5 -- src/assets/icons/circle-plus-fill.svg | 5 -- .../icons/rental-items/8pin-charger.svg | 30 ------- .../icons/rental-items/alcohol-swab.svg | 24 ----- src/assets/icons/rental-items/band-aid.svg | 20 ----- .../icons/rental-items/curling-iron.svg | 22 ----- src/assets/icons/rental-items/default.svg | 14 --- src/assets/icons/rental-items/eye-drops.svg | 21 ----- src/assets/icons/rental-items/hair-dryer.svg | 21 ----- .../icons/rental-items/laptop-charger.svg | 22 ----- src/assets/icons/rental-items/mask.svg | 23 ----- src/assets/icons/rental-items/ointment.svg | 21 ----- .../icons/rental-items/pain-relief-patch.svg | 25 ------ src/assets/icons/rental-items/pill.svg | 21 ----- src/assets/icons/rental-items/power-bank.svg | 21 ----- .../icons/rental-items/sanitary-pad.svg | 21 ----- src/assets/icons/rental-items/umbrella.svg | 22 ----- .../icons/rental-items/usb-c-charger.svg | 23 ----- src/components/ui/ScreenLayout.tsx | 35 ++++++++ src/features/rental/RentalListScreen.tsx | 82 ----------------- .../components/RentalCategoryFilter.tsx | 40 --------- .../rental/components/RentalItemCard.tsx | 90 ------------------- src/features/rental/constants/rentalItems.ts | 75 ---------------- 24 files changed, 56 insertions(+), 651 deletions(-) delete mode 100644 src/assets/icons/circle-minus-fill.svg delete mode 100644 src/assets/icons/circle-plus-fill.svg delete mode 100644 src/assets/icons/rental-items/8pin-charger.svg delete mode 100644 src/assets/icons/rental-items/alcohol-swab.svg delete mode 100644 src/assets/icons/rental-items/band-aid.svg delete mode 100644 src/assets/icons/rental-items/curling-iron.svg delete mode 100644 src/assets/icons/rental-items/default.svg delete mode 100644 src/assets/icons/rental-items/eye-drops.svg delete mode 100644 src/assets/icons/rental-items/hair-dryer.svg delete mode 100644 src/assets/icons/rental-items/laptop-charger.svg delete mode 100644 src/assets/icons/rental-items/mask.svg delete mode 100644 src/assets/icons/rental-items/ointment.svg delete mode 100644 src/assets/icons/rental-items/pain-relief-patch.svg delete mode 100644 src/assets/icons/rental-items/pill.svg delete mode 100644 src/assets/icons/rental-items/power-bank.svg delete mode 100644 src/assets/icons/rental-items/sanitary-pad.svg delete mode 100644 src/assets/icons/rental-items/umbrella.svg delete mode 100644 src/assets/icons/rental-items/usb-c-charger.svg create mode 100644 src/components/ui/ScreenLayout.tsx delete mode 100644 src/features/rental/RentalListScreen.tsx delete mode 100644 src/features/rental/components/RentalCategoryFilter.tsx delete mode 100644 src/features/rental/components/RentalItemCard.tsx delete mode 100644 src/features/rental/constants/rentalItems.ts diff --git a/src/app/App.tsx b/src/app/App.tsx index 6b9a3d1..3b6b0c1 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,10 +1,28 @@ -import RentalListScreen from "@/features/rental/RentalListScreen"; +import { useState } from "react"; -// 라우팅 도입 전까지 임시로 이 화면만 렌더링한다. 데스크톱에서 보기 좋게 아이폰 화면 크기로 가운데 정렬만 해준다. +import type { BottomNavValue } from "@/components/ui/BottomNav"; +import ScreenLayout from "@/components/ui/ScreenLayout"; + +// 라우팅 도입 전까지 ScreenLayout 뼈대 확인용 임시 화면. 실제 화면 콘텐츠는 각 기능 작업에서 채운다. +// 데스크톱에서 보기 좋게 아이폰 화면 크기로 가운데 정렬만 해준다. function App() { + const [bottomNavValue, setBottomNavValue] = useState("home"); + return (
- + +

STREAM

+
+ } + onBottomNavValueChange={setBottomNavValue} + > +
+ 화면 콘텐츠는 각 기능에서 채운다 +
+ ); } diff --git a/src/assets/icons/circle-minus-fill.svg b/src/assets/icons/circle-minus-fill.svg deleted file mode 100644 index ad62883..0000000 --- a/src/assets/icons/circle-minus-fill.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/icons/circle-plus-fill.svg b/src/assets/icons/circle-plus-fill.svg deleted file mode 100644 index b00fa3a..0000000 --- a/src/assets/icons/circle-plus-fill.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/icons/rental-items/8pin-charger.svg b/src/assets/icons/rental-items/8pin-charger.svg deleted file mode 100644 index 481c548..0000000 --- a/src/assets/icons/rental-items/8pin-charger.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/alcohol-swab.svg b/src/assets/icons/rental-items/alcohol-swab.svg deleted file mode 100644 index ec57d64..0000000 --- a/src/assets/icons/rental-items/alcohol-swab.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/band-aid.svg b/src/assets/icons/rental-items/band-aid.svg deleted file mode 100644 index 5456739..0000000 --- a/src/assets/icons/rental-items/band-aid.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/curling-iron.svg b/src/assets/icons/rental-items/curling-iron.svg deleted file mode 100644 index a13d2e6..0000000 --- a/src/assets/icons/rental-items/curling-iron.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/default.svg b/src/assets/icons/rental-items/default.svg deleted file mode 100644 index 8cae4eb..0000000 --- a/src/assets/icons/rental-items/default.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/eye-drops.svg b/src/assets/icons/rental-items/eye-drops.svg deleted file mode 100644 index 5a82cbd..0000000 --- a/src/assets/icons/rental-items/eye-drops.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/hair-dryer.svg b/src/assets/icons/rental-items/hair-dryer.svg deleted file mode 100644 index 6578d26..0000000 --- a/src/assets/icons/rental-items/hair-dryer.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/laptop-charger.svg b/src/assets/icons/rental-items/laptop-charger.svg deleted file mode 100644 index 20df526..0000000 --- a/src/assets/icons/rental-items/laptop-charger.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/mask.svg b/src/assets/icons/rental-items/mask.svg deleted file mode 100644 index b1c90a6..0000000 --- a/src/assets/icons/rental-items/mask.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/ointment.svg b/src/assets/icons/rental-items/ointment.svg deleted file mode 100644 index 2820271..0000000 --- a/src/assets/icons/rental-items/ointment.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/pain-relief-patch.svg b/src/assets/icons/rental-items/pain-relief-patch.svg deleted file mode 100644 index decb03d..0000000 --- a/src/assets/icons/rental-items/pain-relief-patch.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/pill.svg b/src/assets/icons/rental-items/pill.svg deleted file mode 100644 index f399c53..0000000 --- a/src/assets/icons/rental-items/pill.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/power-bank.svg b/src/assets/icons/rental-items/power-bank.svg deleted file mode 100644 index d2c4340..0000000 --- a/src/assets/icons/rental-items/power-bank.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/sanitary-pad.svg b/src/assets/icons/rental-items/sanitary-pad.svg deleted file mode 100644 index 69382ab..0000000 --- a/src/assets/icons/rental-items/sanitary-pad.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/umbrella.svg b/src/assets/icons/rental-items/umbrella.svg deleted file mode 100644 index fbd0e6a..0000000 --- a/src/assets/icons/rental-items/umbrella.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/icons/rental-items/usb-c-charger.svg b/src/assets/icons/rental-items/usb-c-charger.svg deleted file mode 100644 index b8ec969..0000000 --- a/src/assets/icons/rental-items/usb-c-charger.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/ui/ScreenLayout.tsx b/src/components/ui/ScreenLayout.tsx new file mode 100644 index 0000000..8fc52b6 --- /dev/null +++ b/src/components/ui/ScreenLayout.tsx @@ -0,0 +1,35 @@ +import type { ReactNode } from "react"; + +import BottomNav, { type BottomNavValue } from "@/components/ui/BottomNav"; + +interface ScreenLayoutProps { + header: ReactNode; + children: ReactNode; + bottomNavValue: BottomNavValue; + onBottomNavValueChange: (value: BottomNavValue) => void; +} + +// 홈/행사/게시판/빌릴게 등 모든 화면이 공유하는 뼈대 — 고정 크기(375x812) 프레임 안에서 +// header·Bottom Nav는 고정, 본문만 스크롤된다. Top Navigation·필터·리스트 등 화면마다 +// 다른 내용은 header/children으로 각 화면이 채운다(공통인 건 프레임 비율과 Bottom Nav뿐). +function ScreenLayout({ + header, + children, + bottomNavValue, + onBottomNavValueChange, +}: ScreenLayoutProps) { + return ( +
+
{header}
+
{children}
+
+ +
+
+ ); +} + +export default ScreenLayout; diff --git a/src/features/rental/RentalListScreen.tsx b/src/features/rental/RentalListScreen.tsx deleted file mode 100644 index e02b10e..0000000 --- a/src/features/rental/RentalListScreen.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { - SegmentedControl, - SegmentedControlItem, - TopNavigation, - TopNavigationButton, -} from "@wanteddev/wds"; -import { IconBell, IconSearch } from "@wanteddev/wds-icon"; -import { useState } from "react"; - -import BottomNav, { type BottomNavValue } from "@/components/ui/BottomNav"; -import RentalCategoryFilter from "@/features/rental/components/RentalCategoryFilter"; -import RentalItemCard from "@/features/rental/components/RentalItemCard"; -import { RENTAL_ITEMS } from "@/features/rental/constants/rentalItems"; - -// Figma: 빌릴게 (nodeId 1243:73331) -function RentalListScreen() { - const [tab, setTab] = useState("rent"); - const [category, setCategory] = useState("전체"); - const [bottomNavValue, setBottomNavValue] = - useState("rental"); - - return ( -
-
- {/* background 기본값(true)은 iOS 반투명 스타일이라 뒤 배경이 비쳐 보인다. Figma는 별도 배경 없이 화면 배경을 그대로 쓴다. */} - - - 대여 - 반납 - -
- } - trailingContent={ - <> - - - - - - - - } - variant="display" - > - 빌릴게 - -
- -
-
- -
- - {tab === "rent" ? ( -
- {RENTAL_ITEMS.map((item) => ( - - ))} -
- ) : ( -
- 반납 화면은 아직 준비 중이에요 -
- )} -
- -
- -
- - ); -} - -export default RentalListScreen; diff --git a/src/features/rental/components/RentalCategoryFilter.tsx b/src/features/rental/components/RentalCategoryFilter.tsx deleted file mode 100644 index d34d04b..0000000 --- a/src/features/rental/components/RentalCategoryFilter.tsx +++ /dev/null @@ -1,40 +0,0 @@ -const RENTAL_CATEGORIES = [ - "전체", - "전자기기", - "생활잡화", - "상비약", - "위생용품", -]; - -interface RentalCategoryFilterProps { - value: string; - onChange: (category: string) => void; -} - -// Figma: 빌릴게 Filter Row (nodeId 1243:73337) — WDS Chip이 아니라 Stream 로컬 커스텀 칩. -// 카테고리·물품 매핑 API가 아직 없어 필터링 없이 선택 상태만 표시한다. -function RentalCategoryFilter({ value, onChange }: RentalCategoryFilterProps) { - return ( -
- {RENTAL_CATEGORIES.map((category) => { - const active = category === value; - return ( - - ); - })} -
- ); -} - -export default RentalCategoryFilter; diff --git a/src/features/rental/components/RentalItemCard.tsx b/src/features/rental/components/RentalItemCard.tsx deleted file mode 100644 index 3e8a65b..0000000 --- a/src/features/rental/components/RentalItemCard.tsx +++ /dev/null @@ -1,90 +0,0 @@ -// Figma: Rental Item Card (nodeId 1041:61407) -import { Button } from "@wanteddev/wds"; - -import circleMinusFill from "@/assets/icons/circle-minus-fill.svg"; -import circlePlusFill from "@/assets/icons/circle-plus-fill.svg"; - -interface RentalItemCardProps { - icon: string; - itemName: string; - quantity: number; - trailingControl?: "button" | "stepper"; - onRentRequest?: () => void; - stepperValue?: number; - onStepperDecrease?: () => void; - onStepperIncrease?: () => void; -} - -// "대여 신청" 버튼은 Figma상 `Menu/Resource/Action Area/Trailing Content/Button`(WDS) 인스턴스지만, -// 그 이름과 1:1 대응하는 코드 export는 없다 — 대신 WDS `Button`(size="small")이 padding(7px/14px)· -// radius(8px)·타이포(label2)까지 정확히 일치해서 그걸 쓰고, Button 공개 variant엔 없는 "연한 파랑 배경 -// + 파랑 텍스트" 조합만 sx로 보정했다. 스테퍼 +/- 아이콘은 여전히 WDS 미확정이라 하드코딩 — docs/plans 참고. -function RentalItemCard({ - icon, - itemName, - quantity, - trailingControl = "button", - onRentRequest, - stepperValue = 1, - onStepperDecrease, - onStepperIncrease, -}: RentalItemCardProps) { - const isStepper = trailingControl === "stepper"; - - return ( -
-
-
- -
-

- {itemName} -

-

수량 {quantity}

-
-
- - {!isStepper && ( - - )} - - {isStepper && ( -
- - - {stepperValue} - - -
- )} -
-
- ); -} - -export default RentalItemCard; diff --git a/src/features/rental/constants/rentalItems.ts b/src/features/rental/constants/rentalItems.ts deleted file mode 100644 index c3680f9..0000000 --- a/src/features/rental/constants/rentalItems.ts +++ /dev/null @@ -1,75 +0,0 @@ -import eightPinCharger from "@/assets/icons/rental-items/8pin-charger.svg"; -import alcoholSwab from "@/assets/icons/rental-items/alcohol-swab.svg"; -import bandAid from "@/assets/icons/rental-items/band-aid.svg"; -import curlingIron from "@/assets/icons/rental-items/curling-iron.svg"; -import eyeDrops from "@/assets/icons/rental-items/eye-drops.svg"; -import hairDryer from "@/assets/icons/rental-items/hair-dryer.svg"; -import laptopCharger from "@/assets/icons/rental-items/laptop-charger.svg"; -import mask from "@/assets/icons/rental-items/mask.svg"; -import ointment from "@/assets/icons/rental-items/ointment.svg"; -import painReliefPatch from "@/assets/icons/rental-items/pain-relief-patch.svg"; -import pill from "@/assets/icons/rental-items/pill.svg"; -import powerBank from "@/assets/icons/rental-items/power-bank.svg"; -import sanitaryPad from "@/assets/icons/rental-items/sanitary-pad.svg"; -import umbrella from "@/assets/icons/rental-items/umbrella.svg"; -import usbCCharger from "@/assets/icons/rental-items/usb-c-charger.svg"; - -export interface RentalItem { - id: string; - name: string; - quantity: number; - icon: string; -} - -// Figma: 빌릴게 Item Grid (nodeId 1243:73343) 순서·물품명·수량을 그대로 옮긴 목데이터 — 실 API 연동 전까지 사용 -export const RENTAL_ITEMS: RentalItem[] = [ - { icon: curlingIron, id: "curling-iron", name: "고데기", quantity: 28 }, - { - icon: laptopCharger, - id: "laptop-charger", - name: "노트북 충전기(C타입)", - quantity: 28, - }, - { icon: hairDryer, id: "hair-dryer", name: "드라이기", quantity: 28 }, - { icon: mask, id: "mask", name: "마스크", quantity: 28 }, - { icon: bandAid, id: "band-aid", name: "밴드", quantity: 28 }, - { icon: powerBank, id: "power-bank", name: "보조배터리", quantity: 28 }, - { - icon: sanitaryPad, - id: "sanitary-pad-large", - name: "생리대(대형)", - quantity: 28, - }, - { - icon: sanitaryPad, - id: "sanitary-pad-small", - name: "생리대(소형)", - quantity: 28, - }, - { icon: alcoholSwab, id: "alcohol-swab", name: "알콜스왑", quantity: 28 }, - { icon: umbrella, id: "umbrella", name: "우산", quantity: 28 }, - { icon: pill, id: "stomach-medicine", name: "위장약", quantity: 28 }, - { icon: pill, id: "easyen-6", name: "이지엔6", quantity: 28 }, - { icon: eyeDrops, id: "eye-drops", name: "인공눈물", quantity: 28 }, - { icon: pill, id: "cold-medicine", name: "종합감기약", quantity: 28 }, - { - icon: usbCCharger, - id: "usb-c-cable", - name: "케이블(C to C)", - quantity: 28, - }, - { icon: pill, id: "tylenol", name: "타이레놀", quantity: 28 }, - { - icon: painReliefPatch, - id: "pain-relief-patch", - name: "파스", - quantity: 28, - }, - { icon: ointment, id: "ointment", name: "후시딘", quantity: 28 }, - { - icon: eightPinCharger, - id: "8pin-charger", - name: "8핀 충전기", - quantity: 28, - }, -]; From 1a5cb907a1e55a5c6bee307f1d2bd083e491a69e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:38:35 +0900 Subject: [PATCH 6/7] =?UTF-8?q?chore:=20react-router-dom=20=EB=8F=84?= =?UTF-8?q?=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BrowserRouter로 감싸 라우팅 기반을 마련한다 --- package.json | 3 +- pnpm-lock.yaml | 45 ++++++++++ src/assets/icons/circle-minus-fill.svg | 5 ++ src/assets/icons/circle-plus-fill.svg | 5 ++ .../icons/rental-items/8pin-charger.svg | 30 +++++++ .../icons/rental-items/alcohol-swab.svg | 24 +++++ src/assets/icons/rental-items/band-aid.svg | 20 +++++ .../icons/rental-items/curling-iron.svg | 22 +++++ src/assets/icons/rental-items/default.svg | 14 +++ src/assets/icons/rental-items/eye-drops.svg | 21 +++++ src/assets/icons/rental-items/hair-dryer.svg | 21 +++++ .../icons/rental-items/laptop-charger.svg | 22 +++++ src/assets/icons/rental-items/mask.svg | 23 +++++ src/assets/icons/rental-items/ointment.svg | 21 +++++ .../icons/rental-items/pain-relief-patch.svg | 25 ++++++ src/assets/icons/rental-items/pill.svg | 21 +++++ src/assets/icons/rental-items/power-bank.svg | 21 +++++ .../icons/rental-items/sanitary-pad.svg | 21 +++++ src/assets/icons/rental-items/umbrella.svg | 22 +++++ .../icons/rental-items/usb-c-charger.svg | 23 +++++ src/features/rental/RentalListScreen.tsx | 82 +++++++++++++++++ .../components/RentalCategoryFilter.tsx | 40 +++++++++ .../rental/components/RentalItemCard.tsx | 90 +++++++++++++++++++ src/features/rental/constants/rentalItems.ts | 75 ++++++++++++++++ src/main.tsx | 5 +- 25 files changed, 699 insertions(+), 2 deletions(-) create mode 100644 src/assets/icons/circle-minus-fill.svg create mode 100644 src/assets/icons/circle-plus-fill.svg create mode 100644 src/assets/icons/rental-items/8pin-charger.svg create mode 100644 src/assets/icons/rental-items/alcohol-swab.svg create mode 100644 src/assets/icons/rental-items/band-aid.svg create mode 100644 src/assets/icons/rental-items/curling-iron.svg create mode 100644 src/assets/icons/rental-items/default.svg create mode 100644 src/assets/icons/rental-items/eye-drops.svg create mode 100644 src/assets/icons/rental-items/hair-dryer.svg create mode 100644 src/assets/icons/rental-items/laptop-charger.svg create mode 100644 src/assets/icons/rental-items/mask.svg create mode 100644 src/assets/icons/rental-items/ointment.svg create mode 100644 src/assets/icons/rental-items/pain-relief-patch.svg create mode 100644 src/assets/icons/rental-items/pill.svg create mode 100644 src/assets/icons/rental-items/power-bank.svg create mode 100644 src/assets/icons/rental-items/sanitary-pad.svg create mode 100644 src/assets/icons/rental-items/umbrella.svg create mode 100644 src/assets/icons/rental-items/usb-c-charger.svg create mode 100644 src/features/rental/RentalListScreen.tsx create mode 100644 src/features/rental/components/RentalCategoryFilter.tsx create mode 100644 src/features/rental/components/RentalItemCard.tsx create mode 100644 src/features/rental/constants/rentalItems.ts diff --git a/package.json b/package.json index 24403c2..93b6b61 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "@wanteddev/wds": "^3.12.0", "@wanteddev/wds-icon": "^3.12.0", "react": "^19.2.8", - "react-dom": "^19.2.8" + "react-dom": "^19.2.8", + "react-router-dom": "^7.18.3" }, "devDependencies": { "@biomejs/biome": "^2.5.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 891564d..6eb849c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: react-dom: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) + react-router-dom: + specifier: ^7.18.3 + version: 7.18.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8) devDependencies: '@biomejs/biome': specifier: ^2.5.11 @@ -774,6 +777,10 @@ packages: convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + cosmiconfig@7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} @@ -1101,6 +1108,23 @@ packages: '@types/react': optional: true + react-router-dom@7.18.3: + resolution: {integrity: sha512-ytVbyBBM7vMfRCam25r0WMhSVSom909A8p+8m0/f1w853dz/xfFu6etAT2SEbVoSnI+ZoPRDqIsQXVT89gp7kg==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.18.3: + resolution: {integrity: sha512-gyXgtdr5uACJ5b1Q4udzjVV+tb/rlHIMJKuJ0e89R4Kzgz47z/rgP0dIKxktqIEUhDHluGTPJJH/wRha7CyqsA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -1132,6 +1156,9 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1891,6 +1918,8 @@ snapshots: convert-source-map@1.9.0: {} + cookie@1.1.1: {} + cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 @@ -2132,6 +2161,20 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 + react-router-dom@7.18.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + dependencies: + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + react-router: 7.18.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + + react-router@7.18.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + dependencies: + cookie: 1.1.1 + react: 19.2.8 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.8(react@19.2.8) + react-style-singleton@2.2.3(@types/react@19.2.18)(react@19.2.8): dependencies: get-nonce: 1.0.1 @@ -2174,6 +2217,8 @@ snapshots: scheduler@0.27.0: {} + set-cookie-parser@2.7.2: {} + source-map-js@1.2.1: {} source-map@0.5.7: {} diff --git a/src/assets/icons/circle-minus-fill.svg b/src/assets/icons/circle-minus-fill.svg new file mode 100644 index 0000000..ad62883 --- /dev/null +++ b/src/assets/icons/circle-minus-fill.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/circle-plus-fill.svg b/src/assets/icons/circle-plus-fill.svg new file mode 100644 index 0000000..b00fa3a --- /dev/null +++ b/src/assets/icons/circle-plus-fill.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/rental-items/8pin-charger.svg b/src/assets/icons/rental-items/8pin-charger.svg new file mode 100644 index 0000000..481c548 --- /dev/null +++ b/src/assets/icons/rental-items/8pin-charger.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/alcohol-swab.svg b/src/assets/icons/rental-items/alcohol-swab.svg new file mode 100644 index 0000000..ec57d64 --- /dev/null +++ b/src/assets/icons/rental-items/alcohol-swab.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/band-aid.svg b/src/assets/icons/rental-items/band-aid.svg new file mode 100644 index 0000000..5456739 --- /dev/null +++ b/src/assets/icons/rental-items/band-aid.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/curling-iron.svg b/src/assets/icons/rental-items/curling-iron.svg new file mode 100644 index 0000000..a13d2e6 --- /dev/null +++ b/src/assets/icons/rental-items/curling-iron.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/default.svg b/src/assets/icons/rental-items/default.svg new file mode 100644 index 0000000..8cae4eb --- /dev/null +++ b/src/assets/icons/rental-items/default.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/eye-drops.svg b/src/assets/icons/rental-items/eye-drops.svg new file mode 100644 index 0000000..5a82cbd --- /dev/null +++ b/src/assets/icons/rental-items/eye-drops.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/hair-dryer.svg b/src/assets/icons/rental-items/hair-dryer.svg new file mode 100644 index 0000000..6578d26 --- /dev/null +++ b/src/assets/icons/rental-items/hair-dryer.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/laptop-charger.svg b/src/assets/icons/rental-items/laptop-charger.svg new file mode 100644 index 0000000..20df526 --- /dev/null +++ b/src/assets/icons/rental-items/laptop-charger.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/mask.svg b/src/assets/icons/rental-items/mask.svg new file mode 100644 index 0000000..b1c90a6 --- /dev/null +++ b/src/assets/icons/rental-items/mask.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/ointment.svg b/src/assets/icons/rental-items/ointment.svg new file mode 100644 index 0000000..2820271 --- /dev/null +++ b/src/assets/icons/rental-items/ointment.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/pain-relief-patch.svg b/src/assets/icons/rental-items/pain-relief-patch.svg new file mode 100644 index 0000000..decb03d --- /dev/null +++ b/src/assets/icons/rental-items/pain-relief-patch.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/pill.svg b/src/assets/icons/rental-items/pill.svg new file mode 100644 index 0000000..f399c53 --- /dev/null +++ b/src/assets/icons/rental-items/pill.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/power-bank.svg b/src/assets/icons/rental-items/power-bank.svg new file mode 100644 index 0000000..d2c4340 --- /dev/null +++ b/src/assets/icons/rental-items/power-bank.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/sanitary-pad.svg b/src/assets/icons/rental-items/sanitary-pad.svg new file mode 100644 index 0000000..69382ab --- /dev/null +++ b/src/assets/icons/rental-items/sanitary-pad.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/umbrella.svg b/src/assets/icons/rental-items/umbrella.svg new file mode 100644 index 0000000..fbd0e6a --- /dev/null +++ b/src/assets/icons/rental-items/umbrella.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/rental-items/usb-c-charger.svg b/src/assets/icons/rental-items/usb-c-charger.svg new file mode 100644 index 0000000..b8ec969 --- /dev/null +++ b/src/assets/icons/rental-items/usb-c-charger.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/features/rental/RentalListScreen.tsx b/src/features/rental/RentalListScreen.tsx new file mode 100644 index 0000000..e02b10e --- /dev/null +++ b/src/features/rental/RentalListScreen.tsx @@ -0,0 +1,82 @@ +import { + SegmentedControl, + SegmentedControlItem, + TopNavigation, + TopNavigationButton, +} from "@wanteddev/wds"; +import { IconBell, IconSearch } from "@wanteddev/wds-icon"; +import { useState } from "react"; + +import BottomNav, { type BottomNavValue } from "@/components/ui/BottomNav"; +import RentalCategoryFilter from "@/features/rental/components/RentalCategoryFilter"; +import RentalItemCard from "@/features/rental/components/RentalItemCard"; +import { RENTAL_ITEMS } from "@/features/rental/constants/rentalItems"; + +// Figma: 빌릴게 (nodeId 1243:73331) +function RentalListScreen() { + const [tab, setTab] = useState("rent"); + const [category, setCategory] = useState("전체"); + const [bottomNavValue, setBottomNavValue] = + useState("rental"); + + return ( +
+
+ {/* background 기본값(true)은 iOS 반투명 스타일이라 뒤 배경이 비쳐 보인다. Figma는 별도 배경 없이 화면 배경을 그대로 쓴다. */} + + + 대여 + 반납 + +
+ } + trailingContent={ + <> + + + + + + + + } + variant="display" + > + 빌릴게 + +
+ +
+
+ +
+ + {tab === "rent" ? ( +
+ {RENTAL_ITEMS.map((item) => ( + + ))} +
+ ) : ( +
+ 반납 화면은 아직 준비 중이에요 +
+ )} +
+ +
+ +
+ + ); +} + +export default RentalListScreen; diff --git a/src/features/rental/components/RentalCategoryFilter.tsx b/src/features/rental/components/RentalCategoryFilter.tsx new file mode 100644 index 0000000..d34d04b --- /dev/null +++ b/src/features/rental/components/RentalCategoryFilter.tsx @@ -0,0 +1,40 @@ +const RENTAL_CATEGORIES = [ + "전체", + "전자기기", + "생활잡화", + "상비약", + "위생용품", +]; + +interface RentalCategoryFilterProps { + value: string; + onChange: (category: string) => void; +} + +// Figma: 빌릴게 Filter Row (nodeId 1243:73337) — WDS Chip이 아니라 Stream 로컬 커스텀 칩. +// 카테고리·물품 매핑 API가 아직 없어 필터링 없이 선택 상태만 표시한다. +function RentalCategoryFilter({ value, onChange }: RentalCategoryFilterProps) { + return ( +
+ {RENTAL_CATEGORIES.map((category) => { + const active = category === value; + return ( + + ); + })} +
+ ); +} + +export default RentalCategoryFilter; diff --git a/src/features/rental/components/RentalItemCard.tsx b/src/features/rental/components/RentalItemCard.tsx new file mode 100644 index 0000000..3e8a65b --- /dev/null +++ b/src/features/rental/components/RentalItemCard.tsx @@ -0,0 +1,90 @@ +// Figma: Rental Item Card (nodeId 1041:61407) +import { Button } from "@wanteddev/wds"; + +import circleMinusFill from "@/assets/icons/circle-minus-fill.svg"; +import circlePlusFill from "@/assets/icons/circle-plus-fill.svg"; + +interface RentalItemCardProps { + icon: string; + itemName: string; + quantity: number; + trailingControl?: "button" | "stepper"; + onRentRequest?: () => void; + stepperValue?: number; + onStepperDecrease?: () => void; + onStepperIncrease?: () => void; +} + +// "대여 신청" 버튼은 Figma상 `Menu/Resource/Action Area/Trailing Content/Button`(WDS) 인스턴스지만, +// 그 이름과 1:1 대응하는 코드 export는 없다 — 대신 WDS `Button`(size="small")이 padding(7px/14px)· +// radius(8px)·타이포(label2)까지 정확히 일치해서 그걸 쓰고, Button 공개 variant엔 없는 "연한 파랑 배경 +// + 파랑 텍스트" 조합만 sx로 보정했다. 스테퍼 +/- 아이콘은 여전히 WDS 미확정이라 하드코딩 — docs/plans 참고. +function RentalItemCard({ + icon, + itemName, + quantity, + trailingControl = "button", + onRentRequest, + stepperValue = 1, + onStepperDecrease, + onStepperIncrease, +}: RentalItemCardProps) { + const isStepper = trailingControl === "stepper"; + + return ( +
+
+
+ +
+

+ {itemName} +

+

수량 {quantity}

+
+
+ + {!isStepper && ( + + )} + + {isStepper && ( +
+ + + {stepperValue} + + +
+ )} +
+
+ ); +} + +export default RentalItemCard; diff --git a/src/features/rental/constants/rentalItems.ts b/src/features/rental/constants/rentalItems.ts new file mode 100644 index 0000000..c3680f9 --- /dev/null +++ b/src/features/rental/constants/rentalItems.ts @@ -0,0 +1,75 @@ +import eightPinCharger from "@/assets/icons/rental-items/8pin-charger.svg"; +import alcoholSwab from "@/assets/icons/rental-items/alcohol-swab.svg"; +import bandAid from "@/assets/icons/rental-items/band-aid.svg"; +import curlingIron from "@/assets/icons/rental-items/curling-iron.svg"; +import eyeDrops from "@/assets/icons/rental-items/eye-drops.svg"; +import hairDryer from "@/assets/icons/rental-items/hair-dryer.svg"; +import laptopCharger from "@/assets/icons/rental-items/laptop-charger.svg"; +import mask from "@/assets/icons/rental-items/mask.svg"; +import ointment from "@/assets/icons/rental-items/ointment.svg"; +import painReliefPatch from "@/assets/icons/rental-items/pain-relief-patch.svg"; +import pill from "@/assets/icons/rental-items/pill.svg"; +import powerBank from "@/assets/icons/rental-items/power-bank.svg"; +import sanitaryPad from "@/assets/icons/rental-items/sanitary-pad.svg"; +import umbrella from "@/assets/icons/rental-items/umbrella.svg"; +import usbCCharger from "@/assets/icons/rental-items/usb-c-charger.svg"; + +export interface RentalItem { + id: string; + name: string; + quantity: number; + icon: string; +} + +// Figma: 빌릴게 Item Grid (nodeId 1243:73343) 순서·물품명·수량을 그대로 옮긴 목데이터 — 실 API 연동 전까지 사용 +export const RENTAL_ITEMS: RentalItem[] = [ + { icon: curlingIron, id: "curling-iron", name: "고데기", quantity: 28 }, + { + icon: laptopCharger, + id: "laptop-charger", + name: "노트북 충전기(C타입)", + quantity: 28, + }, + { icon: hairDryer, id: "hair-dryer", name: "드라이기", quantity: 28 }, + { icon: mask, id: "mask", name: "마스크", quantity: 28 }, + { icon: bandAid, id: "band-aid", name: "밴드", quantity: 28 }, + { icon: powerBank, id: "power-bank", name: "보조배터리", quantity: 28 }, + { + icon: sanitaryPad, + id: "sanitary-pad-large", + name: "생리대(대형)", + quantity: 28, + }, + { + icon: sanitaryPad, + id: "sanitary-pad-small", + name: "생리대(소형)", + quantity: 28, + }, + { icon: alcoholSwab, id: "alcohol-swab", name: "알콜스왑", quantity: 28 }, + { icon: umbrella, id: "umbrella", name: "우산", quantity: 28 }, + { icon: pill, id: "stomach-medicine", name: "위장약", quantity: 28 }, + { icon: pill, id: "easyen-6", name: "이지엔6", quantity: 28 }, + { icon: eyeDrops, id: "eye-drops", name: "인공눈물", quantity: 28 }, + { icon: pill, id: "cold-medicine", name: "종합감기약", quantity: 28 }, + { + icon: usbCCharger, + id: "usb-c-cable", + name: "케이블(C to C)", + quantity: 28, + }, + { icon: pill, id: "tylenol", name: "타이레놀", quantity: 28 }, + { + icon: painReliefPatch, + id: "pain-relief-patch", + name: "파스", + quantity: 28, + }, + { icon: ointment, id: "ointment", name: "후시딘", quantity: 28 }, + { + icon: eightPinCharger, + id: "8pin-charger", + name: "8핀 충전기", + quantity: 28, + }, +]; diff --git a/src/main.tsx b/src/main.tsx index cd7e812..3a3dd4d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,13 +1,16 @@ import { ThemeProvider } from "@wanteddev/wds"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; +import { BrowserRouter } from "react-router-dom"; import App from "./app/App.tsx"; import "./index.css"; createRoot(document.getElementById("root")!).render( - + + + , ); From f9b37718ee90594f73533cf3382eff1075bea664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9C=EC=A4=80?= <104981505+xeoxxn@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:38:59 +0900 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=EB=B9=8C=EB=A6=B4=EA=B2=8C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=9D=84=20ScreenLayout=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=97=B0=EA=B2=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RentalListScreen이 자체 375x812/BottomNav 대신 공용 ScreenLayout을 쓰도록 리팩터링하고, HomeScreen을 추가해 '/'와 '/rental' 라우트를 연결한다. Bottom Nav 탭 클릭 시 해당 라우트로 이동하도록 연결한다 --- src/app/App.tsx | 26 +++------- src/features/home/HomeScreen.tsx | 41 +++++++++++++++ src/features/rental/RentalListScreen.tsx | 66 +++++++++++++----------- 3 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 src/features/home/HomeScreen.tsx diff --git a/src/app/App.tsx b/src/app/App.tsx index 3b6b0c1..8dd6739 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,28 +1,16 @@ -import { useState } from "react"; +import { Route, Routes } from "react-router-dom"; -import type { BottomNavValue } from "@/components/ui/BottomNav"; -import ScreenLayout from "@/components/ui/ScreenLayout"; +import HomeScreen from "@/features/home/HomeScreen"; +import RentalListScreen from "@/features/rental/RentalListScreen"; -// 라우팅 도입 전까지 ScreenLayout 뼈대 확인용 임시 화면. 실제 화면 콘텐츠는 각 기능 작업에서 채운다. // 데스크톱에서 보기 좋게 아이폰 화면 크기로 가운데 정렬만 해준다. function App() { - const [bottomNavValue, setBottomNavValue] = useState("home"); - return (
- -

STREAM

-
- } - onBottomNavValueChange={setBottomNavValue} - > -
- 화면 콘텐츠는 각 기능에서 채운다 -
- + + } path="/" /> + } path="/rental" /> + ); } diff --git a/src/features/home/HomeScreen.tsx b/src/features/home/HomeScreen.tsx new file mode 100644 index 0000000..7a89447 --- /dev/null +++ b/src/features/home/HomeScreen.tsx @@ -0,0 +1,41 @@ +import { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; + +import type { BottomNavValue } from "@/components/ui/BottomNav"; +import ScreenLayout from "@/components/ui/ScreenLayout"; + +// 홈 화면 콘텐츠는 아직 없어서, 라우팅이 실제로 동작하는지 확인할 placeholder만 둔다. +function HomeScreen() { + const [bottomNavValue, setBottomNavValue] = useState("home"); + const navigate = useNavigate(); + + const handleBottomNavValueChange = (value: BottomNavValue) => { + setBottomNavValue(value); + if (value === "rental") { + navigate("/rental"); + } + }; + + return ( + +

STREAM

+ + } + onBottomNavValueChange={handleBottomNavValueChange} + > +
+

+ 홈 화면은 아직 준비 중이에요 +

+ + 빌릴게 화면 보기 + +
+
+ ); +} + +export default HomeScreen; diff --git a/src/features/rental/RentalListScreen.tsx b/src/features/rental/RentalListScreen.tsx index e02b10e..25e9086 100644 --- a/src/features/rental/RentalListScreen.tsx +++ b/src/features/rental/RentalListScreen.tsx @@ -6,8 +6,10 @@ import { } from "@wanteddev/wds"; import { IconBell, IconSearch } from "@wanteddev/wds-icon"; import { useState } from "react"; +import { useNavigate } from "react-router-dom"; -import BottomNav, { type BottomNavValue } from "@/components/ui/BottomNav"; +import type { BottomNavValue } from "@/components/ui/BottomNav"; +import ScreenLayout from "@/components/ui/ScreenLayout"; import RentalCategoryFilter from "@/features/rental/components/RentalCategoryFilter"; import RentalItemCard from "@/features/rental/components/RentalItemCard"; import { RENTAL_ITEMS } from "@/features/rental/constants/rentalItems"; @@ -18,11 +20,20 @@ function RentalListScreen() { const [category, setCategory] = useState("전체"); const [bottomNavValue, setBottomNavValue] = useState("rental"); + const navigate = useNavigate(); + + const handleBottomNavValueChange = (value: BottomNavValue) => { + setBottomNavValue(value); + if (value === "home") { + navigate("/"); + } + }; return ( -
-
- {/* background 기본값(true)은 iOS 반투명 스타일이라 뒤 배경이 비쳐 보인다. Figma는 별도 배경 없이 화면 배경을 그대로 쓴다. */} + 빌릴게 + } + onBottomNavValueChange={handleBottomNavValueChange} + > +
+
-
-
- + {tab === "rent" ? ( +
+ {RENTAL_ITEMS.map((item) => ( + + ))}
- - {tab === "rent" ? ( -
- {RENTAL_ITEMS.map((item) => ( - - ))} -
- ) : ( -
- 반납 화면은 아직 준비 중이에요 -
- )} -
- -
- -
-
+ ) : ( +
+ 반납 화면은 아직 준비 중이에요 +
+ )} +
); }