From 190fb714b6eb523e6c736895601c7e759adfb451 Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 25 Sep 2026 22:54:44 +0900 Subject: [PATCH 01/12] =?UTF-8?q?chore:=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=ED=8F=89=EB=A9=B4=EB=8F=84=20=ED=99=94=EC=9E=A5=EC=8B=A4=C2=B7?= =?UTF-8?q?=EA=B3=84=EB=8B=A8=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/lockers/restroom.svg | 10 ++++++++++ src/assets/icons/lockers/stairs.svg | 5 +++++ 2 files changed, 15 insertions(+) create mode 100644 src/assets/icons/lockers/restroom.svg create mode 100644 src/assets/icons/lockers/stairs.svg diff --git a/src/assets/icons/lockers/restroom.svg b/src/assets/icons/lockers/restroom.svg new file mode 100644 index 0000000..05419db --- /dev/null +++ b/src/assets/icons/lockers/restroom.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/icons/lockers/stairs.svg b/src/assets/icons/lockers/stairs.svg new file mode 100644 index 0000000..d2eb859 --- /dev/null +++ b/src/assets/icons/lockers/stairs.svg @@ -0,0 +1,5 @@ + + + + + From d8554bab6980f351f0d81fddb690935286095f52 Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 25 Sep 2026 22:54:44 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=20=EC=B9=B4=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 혼잡도 뱃지는 WDS ContentBadge를 쓴다 — 여유/보통/마감 임박은 accent, 마감은 neutral이다. 마감 배경색 토큰(cool-neutral-97)을 새로 추가했다. --- .../lockers/components/LockersZoneCard.tsx | 99 +++++++++++++++++++ .../lockers/constants/lockersZones.ts | 32 ++++++ src/index.css | 4 + 3 files changed, 135 insertions(+) create mode 100644 src/features/lockers/components/LockersZoneCard.tsx create mode 100644 src/features/lockers/constants/lockersZones.ts diff --git a/src/features/lockers/components/LockersZoneCard.tsx b/src/features/lockers/components/LockersZoneCard.tsx new file mode 100644 index 0000000..160cf0d --- /dev/null +++ b/src/features/lockers/components/LockersZoneCard.tsx @@ -0,0 +1,99 @@ +import { ContentBadge, Typography } from "@wanteddev/wds"; + +import type { + LockersZone, + LockersZoneStatus, +} from "@/features/lockers/constants/lockersZones"; + +interface LockersZoneCardProps { + zone: LockersZone; + isSelected: boolean; + onSelect: (zoneId: string) => void; +} + +// 마감은 WDS `color="neutral"`(배경 Fill/Normal)이고 나머지 셋은 `color="accent"`로, +// 배경이 accentColor의 8% 투명도로 깔린다 — 둘 다 Figma와 그대로 맞는다. +// 뱃지 크기는 `xsmall`(padding 3/6 + Caption 2, 11px)이다. 빌릴게 반납 뱃지가 쓰는 `small`은 +// padding 4/6 + Caption 1(12px)이라 이 화면과 다르다. +const STATUS_BADGES = { + almostFull: { + color: "accent", + label: "마감 임박", + token: "semantic.accent.foreground.red", + }, + full: { + color: "neutral", + label: "마감", + token: "semantic.label.alternative", + }, + normal: { + color: "accent", + label: "보통", + token: "semantic.accent.foreground.orange", + }, + spacious: { + color: "accent", + label: "여유", + token: "semantic.accent.foreground.green", + }, +} as const satisfies Record; + +const CONTAINER_CLASS_NAMES = { + full: "bg-cool-neutral-97", + normal: "bg-background-alternative", + selected: "border border-primary bg-primary-subtle", +} as const; + +// Figma: 사물함 구역 선택 Zone Button (nodeId 1737:218476 외) — WDS에 대응 컴포넌트가 없는 +// Stream 로컬 카드다. 안쪽 혼잡도 뱃지만 WDS `ContentBadge`를 쓴다. +// +// 마감 구역은 고를 수 없어서 버튼을 잠근다. Figma에 잠금 상태의 선택 모습이 따로 없는 것도 +// 고를 수 없다는 뜻으로 읽었다. +function LockersZoneCard({ zone, isSelected, onSelect }: LockersZoneCardProps) { + const badge = STATUS_BADGES[zone.status]; + const isFull = zone.status === "full"; + const containerClassName = isSelected + ? CONTAINER_CLASS_NAMES.selected + : CONTAINER_CLASS_NAMES[isFull ? "full" : "normal"]; + + return ( + + ); +} + +export default LockersZoneCard; diff --git a/src/features/lockers/constants/lockersZones.ts b/src/features/lockers/constants/lockersZones.ts new file mode 100644 index 0000000..4c88ee2 --- /dev/null +++ b/src/features/lockers/constants/lockersZones.ts @@ -0,0 +1,32 @@ +// 구역 혼잡도. Figma 목업의 잔여 수량과 뱃지가 서로 맞물리지 않아서(6/6·12/12이 "여유"인데 +// 24/60은 "보통", 24/40은 "마감 임박") 잔여 비율에서 유도하지 않고 데이터로 받는다. +// 임계값 규칙이 정해지면 그때 유도로 바꾼다. +export type LockersZoneStatus = "spacious" | "normal" | "almostFull" | "full"; + +export interface LockersZone { + id: string; + name: string; + status: LockersZoneStatus; + remaining: number; + total: number; +} + +// Figma: 사물함 구역 선택 전 Floor Map (nodeId 1737:218457)의 구역을 그대로 옮긴 목데이터. +// 평면도 배치(231/232호실·화장실·계단·복도)는 데이터가 아니라 LockersFloorMap의 레이아웃이 갖는다. +export const LOCKERS_LEFT_ZONES: LockersZone[] = [ + { id: "A-1", name: "A-1", remaining: 24, status: "spacious", total: 34 }, +]; + +export const LOCKERS_RIGHT_ZONES: LockersZone[] = [ + { id: "A-2", name: "A-2", remaining: 6, status: "spacious", total: 6 }, + { id: "B-1", name: "B-1", remaining: 24, status: "normal", total: 60 }, + { id: "B-2", name: "B-2", remaining: 24, status: "almostFull", total: 40 }, + { id: "C", name: "C", remaining: 0, status: "full", total: 100 }, + { id: "D", name: "D", remaining: 24, status: "spacious", total: 30 }, + { id: "A-3", name: "A-3", remaining: 12, status: "spacious", total: 12 }, +]; + +// 계단 아래에 따로 놓이는 구역 — 평면도상 위치가 달라서 배열을 나눠 둔다. +export const LOCKERS_RIGHT_ZONES_BELOW_STAIRS: LockersZone[] = [ + { id: "A-4", name: "A-4", remaining: 24, status: "spacious", total: 26 }, +]; diff --git a/src/index.css b/src/index.css index 9421301..452df76 100644 --- a/src/index.css +++ b/src/index.css @@ -40,6 +40,10 @@ --color-primary: var(--semantic-primary-normal); --color-primary-subtle: var(--atomic-blue-95); + /* 사물함 구역 선택의 마감 구역 배경(Figma "Cool Neutral/97") — 회색 계열이지만 + Background/Normal/Alternative(#f7f7f8)보다 한 단계 진해서 잠긴 걸 드러낸다 */ + --color-cool-neutral-97: var(--atomic-coolNeutral-97); + --color-status-positive: var(--semantic-status-positive); --color-inverse-background: var(--semantic-inverse-background); From 1b6da054d6d02ffb9b40a7437bcfe12df8acf85f Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 25 Sep 2026 22:54:44 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=20=EC=84=A0=ED=83=9D=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 평면도는 3열 고정 배치다. 호실·화장실·계단 위치는 실제 건물 구조라 레이아웃이 갖고, 구역과 잔여 수량만 데이터에서 온다. --- src/app/router.tsx | 14 +- .../lockers/LockersZoneSelectScreen.tsx | 64 +++++++++ .../lockers/components/LockersFloorMap.tsx | 130 ++++++++++++++++++ 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/features/lockers/LockersZoneSelectScreen.tsx create mode 100644 src/features/lockers/components/LockersFloorMap.tsx diff --git a/src/app/router.tsx b/src/app/router.tsx index db1d4cd..c1d6b6f 100644 --- a/src/app/router.tsx +++ b/src/app/router.tsx @@ -17,6 +17,7 @@ import FeedbacksListScreen from "@/features/feedbacks/FeedbacksListScreen"; import FeedbacksNewScreen from "@/features/feedbacks/FeedbacksNewScreen"; import HomeScreen from "@/features/home/HomeScreen"; import LockersApplyScreen from "@/features/lockers/LockersApplyScreen"; +import LockersZoneSelectScreen from "@/features/lockers/LockersZoneSelectScreen"; import NoticesDetailScreen from "@/features/notices/NoticesDetailScreen"; import NoticesListScreen from "@/features/notices/NoticesListScreen"; @@ -108,7 +109,7 @@ const routes = [ }, { element: , - // 사물함 유의사항 시트 확인용 임시 라우트 — 실제 진입점이 붙으면 화면과 함께 지운다 + // 시트만 있는 화면이라 뒤에 Bottom Nav가 비쳐도 Figma(홈 위에 뜨는 시트)와 같다 path: "/lockers/apply", }, { @@ -121,6 +122,17 @@ const routes = [ } satisfies ScreenRouteHandle, path: "/chat", }, + { + element: , + // Bottom Nav 대신 하단 고정 버튼(Action Area)이 있는 화면. + // 구역 카드 배경이 Background/Normal/Alternative(#f7f7f8)라 화면까지 같은 색이면 + // 카드가 배경에 묻힌다 — Figma대로 흰 면을 깐다. + handle: { + background: "normal", + hasBottomNav: false, + } satisfies ScreenRouteHandle, + path: "/lockers/apply/zones", + }, // 라우트가 없는 경로 — 레이아웃 안에 둬서 하단 탭이 유지되고, 탭 경로(/event 등)면 그 탭이 활성으로 보인다 { element: , path: "*" }, ], diff --git a/src/features/lockers/LockersZoneSelectScreen.tsx b/src/features/lockers/LockersZoneSelectScreen.tsx new file mode 100644 index 0000000..91e623c --- /dev/null +++ b/src/features/lockers/LockersZoneSelectScreen.tsx @@ -0,0 +1,64 @@ +import { + ActionArea, + ActionAreaButton, + TopNavigationButton, +} from "@wanteddev/wds"; +import { IconChevronLeft, IconRefresh } from "@wanteddev/wds-icon"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import ScreenHeader from "@/components/ui/ScreenHeader"; +import { useScreenHeader } from "@/components/ui/useScreenHeader"; +import LockersFloorMap from "@/features/lockers/components/LockersFloorMap"; + +// Figma: 사물함 구역 선택 전 (nodeId 1737:218452), 선택완료 (1737:218489) +// 새로고침은 잔여 수량 API가 붙기 전까지 표시만 한다. +// 선택 후 이동할 화면은 아직 디자인이 없어서 지금은 아무것도 하지 않는다. +function LockersZoneSelectScreen() { + const [selectedZoneId, setSelectedZoneId] = useState(null); + const navigate = useNavigate(); + + useScreenHeader( + navigate(-1)} + variant="icon" + > + + + } + title="사물함 구역 선택" + trailing={ + + + + } + variant="normal" + />, + ); + + return ( +
+
+ +
+ + + {/* 높이 보정 이유는 wds-component-usage.md "Action Area 메인 버튼 높이" 참고 */} + + {selectedZoneId === null ? "구역을 선택해 주세요" : "선택하기"} + + +
+ ); +} + +export default LockersZoneSelectScreen; diff --git a/src/features/lockers/components/LockersFloorMap.tsx b/src/features/lockers/components/LockersFloorMap.tsx new file mode 100644 index 0000000..118e49e --- /dev/null +++ b/src/features/lockers/components/LockersFloorMap.tsx @@ -0,0 +1,130 @@ +import { Typography } from "@wanteddev/wds"; +import { IconChevronUp } from "@wanteddev/wds-icon"; + +import restroomIcon from "@/assets/icons/lockers/restroom.svg"; +import stairsIcon from "@/assets/icons/lockers/stairs.svg"; +import LockersZoneCard from "@/features/lockers/components/LockersZoneCard"; +import { + LOCKERS_LEFT_ZONES, + LOCKERS_RIGHT_ZONES, + LOCKERS_RIGHT_ZONES_BELOW_STAIRS, +} from "@/features/lockers/constants/lockersZones"; + +interface LockersFloorMapProps { + selectedZoneId: string | null; + onSelect: (zoneId: string) => void; +} + +// 호실·화장실처럼 고를 수 없는 자리. 점선 테두리에 라벨만 가운데 둔다. +function MapArea({ + children, + className, +}: { + children: React.ReactNode; + className: string; +}) { + return ( +
+ {children} +
+ ); +} + +function AreaLabel({ icon, label }: { icon?: string; label: string }) { + return ( +
+ {icon !== undefined && ( + + )} + + {label} + +
+ ); +} + +// Figma: 사물함 구역 선택 Floor Map (nodeId 1737:218457) +// 3열 고정 배치다 — 호실·화장실·계단·복도 위치는 실제 건물 구조라 데이터로 받지 않고 +// 여기 레이아웃이 갖는다. 구역 카드와 잔여 수량만 데이터에서 온다. +// 열마다 카드 간격이 다르다(왼쪽 4px, 오른쪽 6px) — Figma 값 그대로다. +function LockersFloorMap({ selectedZoneId, onSelect }: LockersFloorMapProps) { + return ( +
+
+ + + + {LOCKERS_LEFT_ZONES.map((zone) => ( + + ))} + + + + + + +
+ + {/* 가운데 열은 복도다 — 카드가 없고 방향 표시만 있다. + "정릉시장 방향"은 67px 열보다 넓어서 Figma도 한 줄로 넘치게 둔다. */} +
+
+ + + 정릉시장 방향 + +
+ + 복도 + +
+ +
+ {LOCKERS_RIGHT_ZONES.map((zone) => ( + + ))} + + + + {LOCKERS_RIGHT_ZONES_BELOW_STAIRS.map((zone) => ( + + ))} +
+
+ ); +} + +export default LockersFloorMap; From cce1131ba6feca7d2265101dc82f100252eadf01 Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 25 Sep 2026 22:54:44 +0900 Subject: [PATCH 04/12] =?UTF-8?q?refactor:=20=EC=9C=A0=EC=9D=98=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=8B=9C=ED=8A=B8=EB=A5=BC=20=EC=82=AC=EB=AC=BC?= =?UTF-8?q?=ED=95=A8=20=EC=8B=A0=EC=B2=AD=20=ED=9D=90=EB=A6=84=EC=9D=98=20?= =?UTF-8?q?=EC=B2=AB=20=ED=99=94=EB=A9=B4=EC=9C=BC=EB=A1=9C=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 확인용 임시 화면이던 걸 실제 진입 화면으로 바꿨다. 들어오면 시트를 띄우고 확인하면 구역 선택으로 보낸다. 신청 기간 여부는 API 전까지 목 상수로 둔다. --- src/features/lockers/LockersApplyScreen.tsx | 50 ++++++------------- .../lockers/constants/lockersNotice.ts | 4 ++ 2 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/features/lockers/LockersApplyScreen.tsx b/src/features/lockers/LockersApplyScreen.tsx index 5147c13..de6fe85 100644 --- a/src/features/lockers/LockersApplyScreen.tsx +++ b/src/features/lockers/LockersApplyScreen.tsx @@ -1,44 +1,24 @@ -import { Button, Typography } from "@wanteddev/wds"; -import { useState } from "react"; +import { useNavigate } from "react-router-dom"; import LockersNoticeSheet from "@/features/lockers/components/LockersNoticeSheet"; +import { IS_LOCKERS_APPLY_PERIOD } from "@/features/lockers/constants/lockersNotice"; -// 임시 확인용 화면 — 시트를 띄울 진입점이 아직 없어서 둔 자리다. -// 실제 진입점(홈 "사물함 상태" 퀵링크 `1737:218284` 또는 공지 상세 CTA)이 붙으면 -// 이 화면과 /lockers/apply 라우트는 지운다. docs/plans/#68-lockers-notice-sheet.md 참고. +// Figma: 사물함 신청 전 유의사항 (nodeId 1737:218213) +// 신청 흐름의 첫 화면이다 — 들어오면 유의사항 시트부터 띄우고, 확인하면 구역 선택으로 보낸다. +// 시트를 닫으면(딤 탭) 들어온 곳으로 돌아간다. +// +// 이 화면으로 오는 진입점(홈 "사물함 상태" 퀵링크 `1737:218284` 또는 공지 상세 CTA)은 +// 해당 화면을 만들 때 붙인다. function LockersApplyScreen() { - const [isOpen, setIsOpen] = useState(false); - // 시트는 닫아도 380ms 동안 미끄러져 내려간다. 기간 여부를 open과 같은 state에서 파생시키면 - // 그 사이 버튼이 비활성 문구로 바뀌는 게 보이므로, 닫을 때는 open만 끄고 이 값은 유지한다. - const [isApplyPeriod, setIsApplyPeriod] = useState(true); - - const openSheet = (applyPeriod: boolean) => { - setIsApplyPeriod(applyPeriod); - setIsOpen(true); - }; + const navigate = useNavigate(); return ( -
- - 사물함 유의사항 시트 확인용 임시 화면 - - - - - setIsOpen(false)} - // 확인 후 이동할 사물함 구역 선택 화면(1737:218452)은 다음 이슈라 지금은 닫기만 한다 - onConfirm={() => setIsOpen(false)} - open={isOpen} - /> -
+ navigate(-1)} + onConfirm={() => navigate("/lockers/apply/zones")} + open + /> ); } diff --git a/src/features/lockers/constants/lockersNotice.ts b/src/features/lockers/constants/lockersNotice.ts index 3dd7046..acefbb1 100644 --- a/src/features/lockers/constants/lockersNotice.ts +++ b/src/features/lockers/constants/lockersNotice.ts @@ -2,6 +2,10 @@ import applyPeriodIcon from "@/assets/icons/lockers/apply-period.svg"; import onePerPersonIcon from "@/assets/icons/lockers/one-per-person.svg"; import usagePeriodIcon from "@/assets/icons/lockers/usage-period.svg"; +// 지금이 신청 기간인지. 실제 기간 API가 붙기 전까지 이 값을 바꿔서 두 상태를 확인한다 +// (행사 신청 플로우의 목업 제출 결과와 같은 방식). +export const IS_LOCKERS_APPLY_PERIOD = true; + export interface LockersNoticeItem { icon: string; label: string; From 77ecba11f1a64f9d2cd3d11388a925f2d64559f3 Mon Sep 17 00:00:00 2001 From: sangrae Date: Fri, 25 Sep 2026 22:54:44 +0900 Subject: [PATCH 05/12] =?UTF-8?q?docs:=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=20=EC=84=A0=ED=83=9D=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=99=95=EC=A0=95=EB=90=9C=20WDS=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/wds-component-usage.md | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md index 16f817c..619db62 100644 --- a/docs/conventions/wds-component-usage.md +++ b/docs/conventions/wds-component-usage.md @@ -439,3 +439,37 @@ WDS에 이름이 비슷한 `ProgressIndicator`가 실제로 존재해서(`제외 ### `Icon/Feedback`·`Icon/Answer`는 게시판-열린피드백 목록과 같은 로컬 아이콘 이 화면의 "피드백 내용"/"학생회 답변" 아이콘은 목록 화면의 `Icon/Question`/`Icon/Answer`와 이름만 다를 뿐 같은 자리(질문/답변 구분 아이콘)라 새로 받지 않고 기존 `src/assets/icons/feedbacks/{question,answer}.svg`를 그대로 재사용했다. + +## 사물함 구역 선택 화면(`1737:218452`, `1737:218489`) 구현 중 확정된 매핑 + +| WDS 컴포넌트 | 확인 경로 | 비고 | +|---|---|---| +| `Content Badge/Content Badge` | 구역 카드의 혼잡도 뱃지 | `445:5656` — [문서](https://montage.wanted.co.kr/docs/components/contents/content-badge/design) | +| `Icon/Normal/Chevron Up` | 평면도 가운데 열 방향 표시 | `687:24638`, 코드 `IconChevronUp` | + +평면도의 구역 카드·호실·화장실·계단은 전부 Stream 로컬이다. 뱃지만 WDS다. + +### `ContentBadge`의 `size`는 `xsmall`이다 — 빌릴게의 `small`을 베끼면 틀린다 + +`style.js` 실측 결과 세 사이즈가 이렇다. + +| size | padding | 타이포 | +|---|---|---| +| `xsmall` | `3px 6px` | Caption 2 (11px) | +| `small` | `4px 6px` | Caption 1 (12px) | +| `medium` | `5px 8px` | Label 2 (14px) | + +이 화면의 뱃지는 Figma가 `px-6 py-3` + 11px이라 **`xsmall`**이다. `BililgeRentalHistoryEntry.tsx:52`가 쓰는 `small`과 다르다 — "`Content Badge`의 `size`는 화면마다 실측해야 한다" 절의 사례가 하나 더 늘었다. + +혼잡도 3단계는 `color="accent"` + `accentColor`(green/orange/red)로, 배경이 accentColor의 8% 투명도로 깔린다. **마감은 `color="neutral"`**이고 이때 배경은 `semantic.fill.normal`, 글자는 `neutralColor`가 된다(`style.js`의 color 분기 확인) — Figma의 마감 뱃지(`Fill/Normal` 배경 + `Label/Alternative` 글자)와 정확히 맞는다. + +### `download_assets`는 노드 모양에 따라 `export`와 `svgAssets` 중 쓸 게 갈린다 + +- **단일 벡터 레이어**(화장실 `1737:218466`, 계단 `1737:218484`)는 `svgAssets` 항목이 그대로 깨끗한 아이콘이다. `export`를 쓰면 캔버스 배경(``)이 붙는다 +- **여러 레이어 조합**(사물함 유의사항 일러스트)은 `svgAssets`가 레이어별로 쪼개져 나와서 `export`를 써야 하고, 그때 붙는 캔버스 배경을 직접 걷어내야 한다 + +받은 SVG에 `fill="#EFEFEF"`인 전체 크기 ``가 맨 앞에 있으면 캔버스 배경이다. + +### 구역 카드 배경이 화면 배경과 같은 색이라 라우트에 `background: "normal"`이 필요하다 + +카드 배경이 `Background/Normal/Alternative`(`#f7f7f8`)인데 `ScreenLayout` 기본 배경도 같은 값이라, handle을 안 주면 카드가 배경에 완전히 묻힌다(실제로 처음 렌더에서 카드가 안 보였다). Figma 화면 배경이 흰 면이라 `handle: { background: "normal" }`을 준다. From c0d4774f8860c67d9003e8870cecb3771cc622b8 Mon Sep 17 00:00:00 2001 From: sangrae Date: Sun, 27 Sep 2026 00:07:39 +0900 Subject: [PATCH 06/12] =?UTF-8?q?fix:=20=ED=8F=89=EB=A9=B4=EB=8F=84=20?= =?UTF-8?q?=EC=A0=90=EC=84=A0=EC=97=90=20=EC=93=B0=EB=8A=94=20line-solid-n?= =?UTF-8?q?ormal=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 없는 토큰(border-line-solid-normal)을 써서 Tailwind가 클래스를 만들지 못했고 테두리가 currentColor로 떨어져 있었다. Line/Solid/Neutral(#eaebec)과 값이 다른 별개 토큰이다. --- ...kersZoneSelectScreen.tsx => LockersSectionSelectScreen.tsx} | 0 .../components/{LockersZoneCard.tsx => LockersSectionCard.tsx} | 0 .../lockers/constants/{lockersZones.ts => lockersSections.ts} | 0 src/index.css | 3 +++ 4 files changed, 3 insertions(+) rename src/features/lockers/{LockersZoneSelectScreen.tsx => LockersSectionSelectScreen.tsx} (100%) rename src/features/lockers/components/{LockersZoneCard.tsx => LockersSectionCard.tsx} (100%) rename src/features/lockers/constants/{lockersZones.ts => lockersSections.ts} (100%) diff --git a/src/features/lockers/LockersZoneSelectScreen.tsx b/src/features/lockers/LockersSectionSelectScreen.tsx similarity index 100% rename from src/features/lockers/LockersZoneSelectScreen.tsx rename to src/features/lockers/LockersSectionSelectScreen.tsx diff --git a/src/features/lockers/components/LockersZoneCard.tsx b/src/features/lockers/components/LockersSectionCard.tsx similarity index 100% rename from src/features/lockers/components/LockersZoneCard.tsx rename to src/features/lockers/components/LockersSectionCard.tsx diff --git a/src/features/lockers/constants/lockersZones.ts b/src/features/lockers/constants/lockersSections.ts similarity index 100% rename from src/features/lockers/constants/lockersZones.ts rename to src/features/lockers/constants/lockersSections.ts diff --git a/src/index.css b/src/index.css index 452df76..6ef9815 100644 --- a/src/index.css +++ b/src/index.css @@ -20,6 +20,9 @@ ); --color-line-solid-neutral: var(--semantic-line-solid-neutral); + /* Figma "Line/Solid/Normal"(#e1e2e4) — 이름이 비슷한 Line/Solid/Neutral(#eaebec)과 값이 다르다. + 사물함 평면도의 호실·화장실·계단 점선 테두리가 이 값이다. */ + --color-line-solid-normal: var(--semantic-line-solid-normal); --color-line-normal-neutral: var(--semantic-line-normal-neutral); --color-line-solid-alternative: var(--semantic-line-solid-alternative); From 31b7765cc808fc2baf948917197265784a8bc189 Mon Sep 17 00:00:00 2001 From: sangrae Date: Sun, 27 Sep 2026 00:07:39 +0900 Subject: [PATCH 07/12] =?UTF-8?q?refactor:=20=EC=82=AC=EB=AC=BC=ED=95=A8?= =?UTF-8?q?=20=EA=B5=AC=EC=97=AD=20=EC=84=A0=ED=83=9D=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EB=8B=A4=EB=93=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 용어를 zone에서 section으로 통일 (라우트 /lockers/apply/sections 포함) - Figma 치수를 flex 비율로 옮겨 뷰포트 높이·폭을 채우도록 변경. 데스크톱 컬럼(480px)과 큰 폰에서 아래가 비던 문제를 없앤다 - 선택 시에만 테두리가 생겨 콘텐츠가 1px 밀리던 것을 투명 테두리로 고정 - 새로고침 아이콘을 Figma의 Icon/Normal/Reset으로 맞추고 동작 연결 - 미선택일 때도 버튼 문구를 신청하기로 두고 잠그기만 한다 --- src/app/router.tsx | 6 +- src/features/lockers/LockersApplyScreen.tsx | 2 +- .../lockers/LockersSectionSelectScreen.tsx | 33 ++++--- .../lockers/components/LockersFloorMap.tsx | 93 ++++++++++--------- .../lockers/components/LockersSectionCard.tsx | 47 ++++++---- .../lockers/constants/lockersSections.ts | 16 ++-- 6 files changed, 109 insertions(+), 88 deletions(-) diff --git a/src/app/router.tsx b/src/app/router.tsx index c1d6b6f..3c00ff7 100644 --- a/src/app/router.tsx +++ b/src/app/router.tsx @@ -17,7 +17,7 @@ import FeedbacksListScreen from "@/features/feedbacks/FeedbacksListScreen"; import FeedbacksNewScreen from "@/features/feedbacks/FeedbacksNewScreen"; import HomeScreen from "@/features/home/HomeScreen"; import LockersApplyScreen from "@/features/lockers/LockersApplyScreen"; -import LockersZoneSelectScreen from "@/features/lockers/LockersZoneSelectScreen"; +import LockersSectionSelectScreen from "@/features/lockers/LockersSectionSelectScreen"; import NoticesDetailScreen from "@/features/notices/NoticesDetailScreen"; import NoticesListScreen from "@/features/notices/NoticesListScreen"; @@ -123,7 +123,7 @@ const routes = [ path: "/chat", }, { - element: , + element: , // Bottom Nav 대신 하단 고정 버튼(Action Area)이 있는 화면. // 구역 카드 배경이 Background/Normal/Alternative(#f7f7f8)라 화면까지 같은 색이면 // 카드가 배경에 묻힌다 — Figma대로 흰 면을 깐다. @@ -131,7 +131,7 @@ const routes = [ background: "normal", hasBottomNav: false, } satisfies ScreenRouteHandle, - path: "/lockers/apply/zones", + path: "/lockers/apply/sections", }, // 라우트가 없는 경로 — 레이아웃 안에 둬서 하단 탭이 유지되고, 탭 경로(/event 등)면 그 탭이 활성으로 보인다 { element: , path: "*" }, diff --git a/src/features/lockers/LockersApplyScreen.tsx b/src/features/lockers/LockersApplyScreen.tsx index de6fe85..de32929 100644 --- a/src/features/lockers/LockersApplyScreen.tsx +++ b/src/features/lockers/LockersApplyScreen.tsx @@ -16,7 +16,7 @@ function LockersApplyScreen() { navigate(-1)} - onConfirm={() => navigate("/lockers/apply/zones")} + onConfirm={() => navigate("/lockers/apply/sections")} open /> ); diff --git a/src/features/lockers/LockersSectionSelectScreen.tsx b/src/features/lockers/LockersSectionSelectScreen.tsx index 91e623c..7e13e5c 100644 --- a/src/features/lockers/LockersSectionSelectScreen.tsx +++ b/src/features/lockers/LockersSectionSelectScreen.tsx @@ -3,7 +3,7 @@ import { ActionAreaButton, TopNavigationButton, } from "@wanteddev/wds"; -import { IconChevronLeft, IconRefresh } from "@wanteddev/wds-icon"; +import { IconChevronLeft, IconReset } from "@wanteddev/wds-icon"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -12,10 +12,12 @@ import { useScreenHeader } from "@/components/ui/useScreenHeader"; import LockersFloorMap from "@/features/lockers/components/LockersFloorMap"; // Figma: 사물함 구역 선택 전 (nodeId 1737:218452), 선택완료 (1737:218489) -// 새로고침은 잔여 수량 API가 붙기 전까지 표시만 한다. +// 새로고침(Figma Icon/Normal/Reset)은 잔여 수량 API가 없어 지금은 페이지를 다시 읽는다. // 선택 후 이동할 화면은 아직 디자인이 없어서 지금은 아무것도 하지 않는다. -function LockersZoneSelectScreen() { - const [selectedZoneId, setSelectedZoneId] = useState(null); +function LockersSectionSelectScreen() { + const [selectedSectionId, setSelectedSectionId] = useState( + null, + ); const navigate = useNavigate(); useScreenHeader( @@ -31,8 +33,13 @@ function LockersZoneSelectScreen() { } title="사물함 구역 선택" trailing={ - - + window.location.reload()} + variant="icon" + > + } variant="normal" @@ -41,24 +48,26 @@ function LockersZoneSelectScreen() { return (
-
+
{/* 높이 보정 이유는 wds-component-usage.md "Action Area 메인 버튼 높이" 참고 */} + {/* Figma는 미선택일 때 문구가 "구역을 선택해 주세요"로 바뀌지만, + 문구는 그대로 두고 잠그기만 하기로 정했다 */} - {selectedZoneId === null ? "구역을 선택해 주세요" : "선택하기"} + 신청하기
); } -export default LockersZoneSelectScreen; +export default LockersSectionSelectScreen; diff --git a/src/features/lockers/components/LockersFloorMap.tsx b/src/features/lockers/components/LockersFloorMap.tsx index 118e49e..76b2809 100644 --- a/src/features/lockers/components/LockersFloorMap.tsx +++ b/src/features/lockers/components/LockersFloorMap.tsx @@ -1,18 +1,19 @@ import { Typography } from "@wanteddev/wds"; import { IconChevronUp } from "@wanteddev/wds-icon"; +import type { ReactNode } from "react"; import restroomIcon from "@/assets/icons/lockers/restroom.svg"; import stairsIcon from "@/assets/icons/lockers/stairs.svg"; -import LockersZoneCard from "@/features/lockers/components/LockersZoneCard"; +import LockersSectionCard from "@/features/lockers/components/LockersSectionCard"; import { - LOCKERS_LEFT_ZONES, - LOCKERS_RIGHT_ZONES, - LOCKERS_RIGHT_ZONES_BELOW_STAIRS, -} from "@/features/lockers/constants/lockersZones"; + LOCKERS_LEFT_SECTIONS, + LOCKERS_RIGHT_SECTIONS, + LOCKERS_RIGHT_SECTIONS_BELOW_STAIRS, +} from "@/features/lockers/constants/lockersSections"; interface LockersFloorMapProps { - selectedZoneId: string | null; - onSelect: (zoneId: string) => void; + selectedSectionId: string | null; + onSelect: (sectionId: string) => void; } // 호실·화장실처럼 고를 수 없는 자리. 점선 테두리에 라벨만 가운데 둔다. @@ -20,7 +21,7 @@ function MapArea({ children, className, }: { - children: React.ReactNode; + children: ReactNode; className: string; }) { return ( @@ -51,36 +52,48 @@ function AreaLabel({ icon, label }: { icon?: string; label: string }) { } // Figma: 사물함 구역 선택 Floor Map (nodeId 1737:218457) -// 3열 고정 배치다 — 호실·화장실·계단·복도 위치는 실제 건물 구조라 데이터로 받지 않고 -// 여기 레이아웃이 갖는다. 구역 카드와 잔여 수량만 데이터에서 온다. -// 열마다 카드 간격이 다르다(왼쪽 4px, 오른쪽 6px) — Figma 값 그대로다. -function LockersFloorMap({ selectedZoneId, onSelect }: LockersFloorMapProps) { +// +// 호실·화장실·계단·복도 위치는 실제 건물 구조라 데이터로 받지 않고 여기 레이아웃이 갖는다. +// 구역 카드와 잔여 수량만 데이터에서 온다. +// +// Figma는 375×812 한 벌만 그려뒀지만 ScreenLayout은 폰이든 데스크톱(480px 컬럼)이든 높이를 +// 뷰포트로 꽉 채운다. 그래서 치수를 고정하지 않고 **Figma 값을 flex 비율로** 옮겨서 +// 남는 공간을 비례 배분한다 — 열 124:67:124, 왼쪽 열 186:74:186:134, 오른쪽 열 74…34:74. +// 열 사이 간격(10px)과 카드 사이 간격(왼쪽 4px·오른쪽 6px)만 Figma 값 그대로 고정이다. +function LockersFloorMap({ + selectedSectionId, + onSelect, +}: LockersFloorMapProps) { + const renderCard = (section: (typeof LOCKERS_RIGHT_SECTIONS)[number]) => ( + + ); + return ( -
-
- +
+
+ - {LOCKERS_LEFT_ZONES.map((zone) => ( - - ))} - + {LOCKERS_LEFT_SECTIONS.map(renderCard)} + - +
{/* 가운데 열은 복도다 — 카드가 없고 방향 표시만 있다. - "정릉시장 방향"은 67px 열보다 넓어서 Figma도 한 줄로 넘치게 둔다. */} -
-
+ 빈 칸도 Figma 비율(위 32 / 라벨 사이 176 / 아래 330)을 flex로 옮긴다. + "정릉시장 방향"은 열보다 넓어서 Figma처럼 한 줄로 넘치게 둔다. */} +
+
+
+
복도 +
-
- {LOCKERS_RIGHT_ZONES.map((zone) => ( - - ))} - +
+ {LOCKERS_RIGHT_SECTIONS.map(renderCard)} + - {LOCKERS_RIGHT_ZONES_BELOW_STAIRS.map((zone) => ( - - ))} + {LOCKERS_RIGHT_SECTIONS_BELOW_STAIRS.map(renderCard)}
); diff --git a/src/features/lockers/components/LockersSectionCard.tsx b/src/features/lockers/components/LockersSectionCard.tsx index 160cf0d..5e4ef18 100644 --- a/src/features/lockers/components/LockersSectionCard.tsx +++ b/src/features/lockers/components/LockersSectionCard.tsx @@ -1,14 +1,14 @@ import { ContentBadge, Typography } from "@wanteddev/wds"; import type { - LockersZone, - LockersZoneStatus, -} from "@/features/lockers/constants/lockersZones"; + LockersSection, + LockersSectionStatus, +} from "@/features/lockers/constants/lockersSections"; -interface LockersZoneCardProps { - zone: LockersZone; +interface LockersSectionCardProps { + section: LockersSection; isSelected: boolean; - onSelect: (zoneId: string) => void; + onSelect: (sectionId: string) => void; } // 마감은 WDS `color="neutral"`(배경 Fill/Normal)이고 나머지 셋은 `color="accent"`로, @@ -36,31 +36,38 @@ const STATUS_BADGES = { label: "여유", token: "semantic.accent.foreground.green", }, -} as const satisfies Record; +} as const satisfies Record; +// 선택됐을 때만 테두리가 생기면 콘텐츠 박스가 1px씩 줄어서 가운데 정렬된 내용이 밀린다. +// 항상 1px 테두리를 두되 평소엔 투명으로 둬서 박스 크기를 고정한다 +// (배경이 테두리 자리까지 깔려서 테두리 없는 것과 똑같이 보인다). const CONTAINER_CLASS_NAMES = { - full: "bg-cool-neutral-97", - normal: "bg-background-alternative", - selected: "border border-primary bg-primary-subtle", + full: "border-transparent bg-cool-neutral-97", + normal: "border-transparent bg-background-alternative", + selected: "border-primary bg-primary-subtle", } as const; -// Figma: 사물함 구역 선택 Zone Button (nodeId 1737:218476 외) — WDS에 대응 컴포넌트가 없는 +// Figma: 사물함 구역 선택 Zone Button (nodeId 1737:218476 외 — Figma 레이어 이름은 Zone이다) — WDS에 대응 컴포넌트가 없는 // Stream 로컬 카드다. 안쪽 혼잡도 뱃지만 WDS `ContentBadge`를 쓴다. // // 마감 구역은 고를 수 없어서 버튼을 잠근다. Figma에 잠금 상태의 선택 모습이 따로 없는 것도 // 고를 수 없다는 뜻으로 읽었다. -function LockersZoneCard({ zone, isSelected, onSelect }: LockersZoneCardProps) { - const badge = STATUS_BADGES[zone.status]; - const isFull = zone.status === "full"; +function LockersSectionCard({ + section, + isSelected, + onSelect, +}: LockersSectionCardProps) { + const badge = STATUS_BADGES[section.status]; + const isFull = section.status === "full"; const containerClassName = isSelected ? CONTAINER_CLASS_NAMES.selected : CONTAINER_CLASS_NAMES[isFull ? "full" : "normal"]; return ( ); } -export default LockersZoneCard; +export default LockersSectionCard; diff --git a/src/features/lockers/constants/lockersSections.ts b/src/features/lockers/constants/lockersSections.ts index 4c88ee2..a838253 100644 --- a/src/features/lockers/constants/lockersSections.ts +++ b/src/features/lockers/constants/lockersSections.ts @@ -1,23 +1,27 @@ // 구역 혼잡도. Figma 목업의 잔여 수량과 뱃지가 서로 맞물리지 않아서(6/6·12/12이 "여유"인데 // 24/60은 "보통", 24/40은 "마감 임박") 잔여 비율에서 유도하지 않고 데이터로 받는다. // 임계값 규칙이 정해지면 그때 유도로 바꾼다. -export type LockersZoneStatus = "spacious" | "normal" | "almostFull" | "full"; +export type LockersSectionStatus = + | "spacious" + | "normal" + | "almostFull" + | "full"; -export interface LockersZone { +export interface LockersSection { id: string; name: string; - status: LockersZoneStatus; + status: LockersSectionStatus; remaining: number; total: number; } // Figma: 사물함 구역 선택 전 Floor Map (nodeId 1737:218457)의 구역을 그대로 옮긴 목데이터. // 평면도 배치(231/232호실·화장실·계단·복도)는 데이터가 아니라 LockersFloorMap의 레이아웃이 갖는다. -export const LOCKERS_LEFT_ZONES: LockersZone[] = [ +export const LOCKERS_LEFT_SECTIONS: LockersSection[] = [ { id: "A-1", name: "A-1", remaining: 24, status: "spacious", total: 34 }, ]; -export const LOCKERS_RIGHT_ZONES: LockersZone[] = [ +export const LOCKERS_RIGHT_SECTIONS: LockersSection[] = [ { id: "A-2", name: "A-2", remaining: 6, status: "spacious", total: 6 }, { id: "B-1", name: "B-1", remaining: 24, status: "normal", total: 60 }, { id: "B-2", name: "B-2", remaining: 24, status: "almostFull", total: 40 }, @@ -27,6 +31,6 @@ export const LOCKERS_RIGHT_ZONES: LockersZone[] = [ ]; // 계단 아래에 따로 놓이는 구역 — 평면도상 위치가 달라서 배열을 나눠 둔다. -export const LOCKERS_RIGHT_ZONES_BELOW_STAIRS: LockersZone[] = [ +export const LOCKERS_RIGHT_SECTIONS_BELOW_STAIRS: LockersSection[] = [ { id: "A-4", name: "A-4", remaining: 24, status: "spacious", total: 26 }, ]; From 730aaf76553ea01776b128573a7943187fe6e50e Mon Sep 17 00:00:00 2001 From: sangrae Date: Sun, 27 Sep 2026 00:07:39 +0900 Subject: [PATCH 08/12] =?UTF-8?q?docs:=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=EA=B5=AC=EC=97=AD=20=EC=84=A0=ED=83=9D=20=EB=A7=A4=ED=95=91?= =?UTF-8?q?=EC=97=90=20Reset=20=EC=95=84=EC=9D=B4=EC=BD=98=C2=B7=EC=A0=90?= =?UTF-8?q?=EC=84=A0=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conventions/wds-component-usage.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conventions/wds-component-usage.md b/docs/conventions/wds-component-usage.md index 619db62..3f996e7 100644 --- a/docs/conventions/wds-component-usage.md +++ b/docs/conventions/wds-component-usage.md @@ -446,6 +446,7 @@ WDS에 이름이 비슷한 `ProgressIndicator`가 실제로 존재해서(`제외 |---|---|---| | `Content Badge/Content Badge` | 구역 카드의 혼잡도 뱃지 | `445:5656` — [문서](https://montage.wanted.co.kr/docs/components/contents/content-badge/design) | | `Icon/Normal/Chevron Up` | 평면도 가운데 열 방향 표시 | `687:24638`, 코드 `IconChevronUp` | +| `Icon/Normal/Reset` | Top Navigation 트레일링 새로고침 | `790:38150` — "초기화를 표현합니다 / 반시계 화살표". **`IconRefresh`가 아니라 `IconReset`이다** — wds-icon에 Refresh·Reset·Rotate가 다 있어서 이름만 보고 고르면 틀린다 | 평면도의 구역 카드·호실·화장실·계단은 전부 Stream 로컬이다. 뱃지만 WDS다. From b3c70f8c8048759829862d13a5f5bb5e8ae11077 Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 1 Oct 2026 17:02:50 +0900 Subject: [PATCH 09/12] =?UTF-8?q?fix:=20=EA=B5=AC=EC=97=AD=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EB=B2=84=ED=8A=BC=20=EB=AC=B8=EA=B5=AC=EB=A5=BC=20?= =?UTF-8?q?Figma=EB=8C=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/lockers/LockersSectionSelectScreen.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/lockers/LockersSectionSelectScreen.tsx b/src/features/lockers/LockersSectionSelectScreen.tsx index 7e13e5c..ab83522 100644 --- a/src/features/lockers/LockersSectionSelectScreen.tsx +++ b/src/features/lockers/LockersSectionSelectScreen.tsx @@ -57,13 +57,13 @@ function LockersSectionSelectScreen() { {/* 높이 보정 이유는 wds-component-usage.md "Action Area 메인 버튼 높이" 참고 */} - {/* Figma는 미선택일 때 문구가 "구역을 선택해 주세요"로 바뀌지만, - 문구는 그대로 두고 잠그기만 하기로 정했다 */} - 신청하기 + {selectedSectionId === null + ? "사물함 구역을 선택해 주세요" + : "선택 완료"}
From ad10a894ab0f0bc8a8e940ab40425284353747c7 Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 1 Oct 2026 17:02:50 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20=EA=B5=AC=EC=97=AD=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EC=9E=94=EC=97=AC=20=EC=88=98=EB=9F=89?= =?UTF-8?q?=EC=9D=84=20Typography=EB=A1=9C=20=ED=91=9C=EC=8B=9C=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EC=84=A0=ED=83=9D=20=EC=83=81=ED=83=9C=EB=A5=BC=20?= =?UTF-8?q?aria-pressed=EB=A1=9C=20=EC=95=8C=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/lockers/components/LockersSectionCard.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/features/lockers/components/LockersSectionCard.tsx b/src/features/lockers/components/LockersSectionCard.tsx index 5e4ef18..2da47db 100644 --- a/src/features/lockers/components/LockersSectionCard.tsx +++ b/src/features/lockers/components/LockersSectionCard.tsx @@ -65,6 +65,7 @@ function LockersSectionCard({ return ( ); From 9408b74b84347fca2a4b7ab18cbdde2adcba6365 Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 1 Oct 2026 17:02:50 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20=EB=82=AE=EC=9D=80=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=97=90=EC=84=9C=20=ED=8F=89=EB=A9=B4=EB=8F=84?= =?UTF-8?q?=EA=B0=80=20=EC=9E=98=EB=A6=AC=EC=A7=80=20=EC=95=8A=EA=B2=8C=20?= =?UTF-8?q?=EC=84=B8=EB=A1=9C=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=ED=97=88?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/lockers/LockersSectionSelectScreen.tsx | 2 +- src/features/lockers/components/LockersFloorMap.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/lockers/LockersSectionSelectScreen.tsx b/src/features/lockers/LockersSectionSelectScreen.tsx index ab83522..4fc4175 100644 --- a/src/features/lockers/LockersSectionSelectScreen.tsx +++ b/src/features/lockers/LockersSectionSelectScreen.tsx @@ -48,7 +48,7 @@ function LockersSectionSelectScreen() { return (
-
+
+
From b2be3cf0bd95cff861880f21d1ad336e614acb4f Mon Sep 17 00:00:00 2001 From: sangrae Date: Thu, 1 Oct 2026 17:02:50 +0900 Subject: [PATCH 12/12] =?UTF-8?q?fix:=20=EC=9C=A0=EC=9D=98=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=8B=9C=ED=8A=B8=EA=B0=80=20=EC=97=B4=EB=A6=AC?= =?UTF-8?q?=EA=B3=A0=20=EB=8B=AB=ED=9E=90=20=EB=95=8C=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=EC=9D=B4=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=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/features/lockers/LockersApplyScreen.tsx | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/features/lockers/LockersApplyScreen.tsx b/src/features/lockers/LockersApplyScreen.tsx index de32929..99eb32e 100644 --- a/src/features/lockers/LockersApplyScreen.tsx +++ b/src/features/lockers/LockersApplyScreen.tsx @@ -1,8 +1,12 @@ +import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import LockersNoticeSheet from "@/features/lockers/components/LockersNoticeSheet"; import { IS_LOCKERS_APPLY_PERIOD } from "@/features/lockers/constants/lockersNotice"; +// BottomSheet의 시트 내려가는 시간(duration-[380ms])과 맞춘다 — 다 내려간 뒤에 화면을 떠난다 +const SHEET_CLOSE_MS = 380; + // Figma: 사물함 신청 전 유의사항 (nodeId 1737:218213) // 신청 흐름의 첫 화면이다 — 들어오면 유의사항 시트부터 띄우고, 확인하면 구역 선택으로 보낸다. // 시트를 닫으면(딤 탭) 들어온 곳으로 돌아간다. @@ -11,13 +15,28 @@ import { IS_LOCKERS_APPLY_PERIOD } from "@/features/lockers/constants/lockersNot // 해당 화면을 만들 때 붙인다. function LockersApplyScreen() { const navigate = useNavigate(); + const [isOpen, setIsOpen] = useState(false); + + // 처음부터 open으로 그리면 시트가 올라오는 전환 없이 바로 떠 있다. 닫힌 상태가 한 번 그려진 뒤 + // 열어야 BottomSheet의 전환이 보여서 두 프레임 뒤에 연다. + useEffect(() => { + let frameId = requestAnimationFrame(() => { + frameId = requestAnimationFrame(() => setIsOpen(true)); + }); + return () => cancelAnimationFrame(frameId); + }, []); + + const handleClose = () => { + setIsOpen(false); + setTimeout(() => navigate(-1), SHEET_CLOSE_MS); + }; return ( navigate(-1)} + onClose={handleClose} onConfirm={() => navigate("/lockers/apply/sections")} - open + open={isOpen} /> ); }