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/app/App.tsx b/src/app/App.tsx index d347dd4..8dd6739 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,8 +1,17 @@ +import { Route, Routes } from "react-router-dom"; + +import HomeScreen from "@/features/home/HomeScreen"; +import RentalListScreen from "@/features/rental/RentalListScreen"; + +// 데스크톱에서 보기 좋게 아이폰 화면 크기로 가운데 정렬만 해준다. function App() { return ( -
-

STREAM

-
+
+ + } path="/" /> + } path="/rental" /> + +
); } 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 @@ + + + + + + + + + + + + + + + + + + + + + + + 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; 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/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 new file mode 100644 index 0000000..25e9086 --- /dev/null +++ b/src/features/rental/RentalListScreen.tsx @@ -0,0 +1,88 @@ +import { + SegmentedControl, + SegmentedControlItem, + TopNavigation, + TopNavigationButton, +} from "@wanteddev/wds"; +import { IconBell, IconSearch } from "@wanteddev/wds-icon"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +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"; + +// Figma: 빌릴게 (nodeId 1243:73331) +function RentalListScreen() { + const [tab, setTab] = useState("rent"); + const [category, setCategory] = useState("전체"); + const [bottomNavValue, setBottomNavValue] = + useState("rental"); + const navigate = useNavigate(); + + const handleBottomNavValueChange = (value: BottomNavValue) => { + setBottomNavValue(value); + if (value === "home") { + navigate("/"); + } + }; + + return ( + + + 대여 + 반납 + + + } + trailingContent={ + <> + + + + + + + + } + variant="display" + > + 빌릴게 + + } + onBottomNavValueChange={handleBottomNavValueChange} + > +
+ +
+ + {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/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..3a3dd4d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,14 +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"; -import "@wanteddev/wds/global.css"; createRoot(document.getElementById("root")!).render( - + + + , );