관망도 분석도구 위치 조정
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
import { useEffect, useState, type ComponentType, type ReactNode } from "react";
|
||||
import {
|
||||
ChartColumnBig,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
PanelsTopLeft,
|
||||
PencilRuler,
|
||||
Search,
|
||||
@@ -61,11 +61,19 @@ const ANALYSIS_POPUP_ITEMS: Array<{
|
||||
{ key: "infoSearch", label: "정보검색", icon: Search },
|
||||
{ key: "pipeAnalysisPopup", label: "관로분석", icon: ChartColumnBig },
|
||||
{ key: "floodPredictionMapPopup", label: "침수예측지도", icon: Waves },
|
||||
{ key: "agedPipeStatusByCtpvPopup", label: "시도별 노후관로현황", icon: ChartColumnBig },
|
||||
{
|
||||
key: "agedPipeStatusByCtpvPopup",
|
||||
label: "시도별 노후관로현황",
|
||||
icon: ChartColumnBig,
|
||||
},
|
||||
{ key: "gisEditPopup", label: "GIS 편집", icon: PencilRuler },
|
||||
{ key: "gisManagementPopup", label: "GIS 관리", icon: Settings2 },
|
||||
{ key: "flowRiskPopup", label: "통수 위험", icon: TriangleAlert },
|
||||
{ key: "inftwtResultPopup", label: "침입수 분석결과", renderIcon: InftwtMenuIcon },
|
||||
{
|
||||
key: "inftwtResultPopup",
|
||||
label: "침입수 분석결과",
|
||||
renderIcon: InftwtMenuIcon,
|
||||
},
|
||||
{ key: "rdiiResultPopup", label: "RDII 분석결과", icon: ChartColumnBig },
|
||||
];
|
||||
|
||||
@@ -78,7 +86,9 @@ export default function AnalysisPopupMenu({
|
||||
initialActiveKey = null,
|
||||
}: Props) {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const [activeKey, setActiveKey] = useState<WindowPopupKey | "infoSearch" | null>(initialActiveKey);
|
||||
const [activeKey, setActiveKey] = useState<
|
||||
WindowPopupKey | "infoSearch" | null
|
||||
>(initialActiveKey);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isGisEditActive && activeKey === "gisEditPopup") {
|
||||
@@ -98,21 +108,36 @@ export default function AnalysisPopupMenu({
|
||||
}, [initialActiveKey]);
|
||||
|
||||
return (
|
||||
<div className="absolute right-[0.55rem] top-[20px] z-[45]">
|
||||
<div className="relative">
|
||||
{isOpen ? (
|
||||
<div className="absolute right-[28px] w-[154px] overflow-hidden rounded-[6px] border border-border bg-background shadow-[0_8px_18px_rgba(15,23,42,0.14)]">
|
||||
<div className="flex h-[36px] items-center gap-2 border-b border-border bg-secondary px-[10px] text-[13px] font-bold text-foreground">
|
||||
<div className="absolute right-[15px] top-[8px] z-[45]">
|
||||
<div className="flex w-[154px] flex-col overflow-hidden rounded-[6px] border border-border bg-background shadow-[0_8px_18px_rgba(15,23,42,0.14)]">
|
||||
<div className="flex h-[36px] shrink-0 items-center justify-between gap-2 border-b border-border bg-secondary pl-[10px] pr-[4px] text-[13px] font-bold text-foreground">
|
||||
<div className="flex items-center gap-2">
|
||||
<PanelsTopLeft className="h-4 w-4 text-primary" />
|
||||
<span>분석도구</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-[28px] w-[28px] shrink-0 items-center justify-center rounded-[4px] text-label transition hover:bg-accent hover:text-primary"
|
||||
onClick={() => setIsOpen((value) => !value)}
|
||||
title={isOpen ? "분석 메뉴 숨기기" : "분석 메뉴 보이기"}
|
||||
aria-label={isOpen ? "분석 메뉴 숨기기" : "분석 메뉴 보이기"}
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
{isOpen ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 p-[6px]">
|
||||
{isOpen ? (
|
||||
<div className="flex flex-col gap-[3px] p-[6px]">
|
||||
{ANALYSIS_POPUP_ITEMS.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const isActive = item.key === "gisEditPopup"
|
||||
const isActive =
|
||||
item.key === "gisEditPopup"
|
||||
? isGisEditActive
|
||||
: activeKey === item.key;
|
||||
|
||||
@@ -120,9 +145,9 @@ export default function AnalysisPopupMenu({
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className={`relative flex h-[34px] items-center gap-[7px] rounded-[5px] border px-[8px] pl-[10px] text-left text-[12px] font-semibold transition ${
|
||||
className={`relative flex h-[33px] items-center gap-[7px] rounded-[5px] border px-[8px] pl-[10px] text-left text-[12px] font-semibold transition ${
|
||||
isActive
|
||||
? "border-primary bg-secondary font-bold text-primary before:absolute before:left-0 before:top-[7px] before:bottom-[7px] before:w-[3px] before:rounded-r-[2px] before:bg-primary"
|
||||
? "border-primary bg-secondary font-bold text-primary before:absolute before:bottom-[7px] before:left-0 before:top-[7px] before:w-[3px] before:rounded-r-[2px] before:bg-primary"
|
||||
: "border-transparent bg-background text-foreground hover:border-border hover:bg-accent hover:text-primary"
|
||||
}`}
|
||||
onClick={() => {
|
||||
@@ -167,18 +192,7 @@ export default function AnalysisPopupMenu({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-0 top-0 flex h-[36px] w-[20px] items-center justify-center rounded-[4px] border border-border bg-background text-label shadow-[0_8px_18px_rgba(15,23,42,0.14)] transition hover:bg-accent hover:text-primary"
|
||||
onClick={() => setIsOpen((value) => !value)}
|
||||
title={isOpen ? "분석 메뉴 접기" : "분석 메뉴 펼치기"}
|
||||
aria-label={isOpen ? "분석 메뉴 접기" : "분석 메뉴 펼치기"}
|
||||
>
|
||||
{isOpen ? <ChevronRight className="h-4 w-4" /> : <ChevronLeft className="h-4 w-4" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7850,7 +7850,7 @@ const Map = () => {
|
||||
.sn-map-control-layout .mapbtn {
|
||||
top: auto;
|
||||
right: 15px;
|
||||
bottom: 451px;
|
||||
bottom: 439px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .custom-toolbar {
|
||||
@@ -7860,12 +7860,12 @@ const Map = () => {
|
||||
.sn-map-control-layout .tool-bar {
|
||||
top: auto;
|
||||
right: 15px;
|
||||
bottom: 248px;
|
||||
bottom: 230px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .zoom-level-control {
|
||||
right: 16px;
|
||||
bottom: 56px;
|
||||
right: 15px;
|
||||
bottom: 36px;
|
||||
}
|
||||
|
||||
.sn-map-control-layout .zoom-level-summary {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# FE-MAP 우측 도구 배치 개선 구현 기록
|
||||
|
||||
## 작업 목적
|
||||
|
||||
- 지도 우측의 분석도구 펼침·숨김 버튼을 분석도구 제목 영역 안으로 이동한다.
|
||||
- 분석도구, 지도 선택 버튼, 지도 도구 모음, 줌 컨트롤의 우측 기준선을 통일한다.
|
||||
- 우측 도구를 위아래로 재배치해 도구 사이의 겹침을 제거한다.
|
||||
|
||||
## 원본 요구사항 추적 근거
|
||||
|
||||
- `D:\workspace\IIPBS\docs\기준문서\화면설계서.pptx`
|
||||
- 슬라이드 12: `SFR-011-003`, 화면 ID `SN_MN010105`, 관로분석·GIS 편집·GIS 관리·통수위험 등 분석도구 구성
|
||||
- 슬라이드 14, 16: 지도 우측 분석도구 배치 패턴
|
||||
- 슬라이드 32: `SFR-012-003`, `SFR-012-004`, 화면 ID `SN_MN010301`, GIS 편집
|
||||
- 슬라이드 33: `SFR-012-002`, 화면 ID `SN_MN010302`, GIS 관리
|
||||
- `D:\workspace\IIPBS\docs\기준문서\요구사항정의서.xlsx`
|
||||
- 시트 `3. (기능)요구사항정의 및 추적표`, 행 89~92: `SFR-011-003`~`SFR-011-006`
|
||||
- 같은 시트 행 97~99: `SFR-012-002`~`SFR-012-004`
|
||||
|
||||
이번 변경은 원본에 정의된 분석 기능이나 동작 계약을 변경하지 않고, 해당 도구의 화면 배치와 접기·펼치기 UI만 개선한다.
|
||||
|
||||
## 수정 대상
|
||||
|
||||
- `app/(map-layout)/map/components/analysisMenu/AnalysisPopupMenu.tsx`
|
||||
- `app/(map-layout)/map/page.tsx`
|
||||
|
||||
## 변경 내용
|
||||
|
||||
- 분석도구 토글을 외부 돌출 버튼에서 제목 우측의 내부 버튼으로 변경했다.
|
||||
- 토글에 `aria-label`, `aria-expanded`를 적용하고 접힘 상태에서도 제목 바는 유지하도록 했다.
|
||||
- 분석도구를 지도 영역 우측 15px 기준으로 고정하고 다른 도구의 우측 기준선도 15px로 통일했다.
|
||||
- 분석도구 항목 높이와 간격을 소폭 조정하고, 하단 지도 도구들의 `bottom` 위치를 재배치했다.
|
||||
|
||||
## 영향 범위
|
||||
|
||||
- 프론트엔드 `sn` 지도 화면의 우측 도구 배치에만 영향이 있다.
|
||||
- API, 상태관리 계약, 백엔드, DB 스키마 영향은 없다.
|
||||
|
||||
## 테스트 및 검증
|
||||
|
||||
- 변경 내용 검사: `git diff --check` 통과
|
||||
- 개발 서버의 Turbopack 컴파일 및 실제 화면 반영 확인
|
||||
- 실제 브라우저 검증: `http://localhost:3002/map`, 1920×912 뷰포트
|
||||
- 분석도구 우측 좌표: 1905px
|
||||
- 지도 선택 버튼·지도 도구 모음·줌 컨트롤 우측 좌표: 모두 1905px
|
||||
- 분석도구→지도 선택 버튼 간격: 6px
|
||||
- 지도 선택 버튼→지도 도구 모음 간격: 4px
|
||||
- 지도 도구 모음→줌 컨트롤 간격: 4px
|
||||
- 숨김 시 `aria-expanded=false`, 분석 메뉴 항목 0개, 제목 바 유지 확인
|
||||
- 보이기 시 `aria-expanded=true`, 분석 메뉴 항목 9개 확인
|
||||
- 검증 화면: `D:\workspace\IIPBS\docs\작업내용\FE-MAP-우측도구배치\검증\20260811-분석도구-우측도구-정렬.png`
|
||||
|
||||
## 롤백 방법
|
||||
|
||||
- 위 두 소스 파일에서 본 작업의 분석도구 헤더/토글 구조와 우측 도구 위치값 변경을 되돌린다.
|
||||
- 구현 기록과 검증 이미지를 제거한다.
|
||||
|
||||
## 남은 리스크
|
||||
|
||||
- 사용자 실행 중인 Next 개발 서버 보호를 위해 별도 프로덕션 빌드는 수행하지 않았다.
|
||||
- ESLint는 기존 `apps/sn/eslint.config.mjs`의 배열 전개 오류로, TypeScript 전체 검사는 기존 `tsconfig.json`의 `ignoreDeprecations` 설정 오류로 각각 대상 코드 검사 전에 중단됐다.
|
||||
- 사용자 제보 화면과 동일한 1920×912 크기의 실제 브라우저에서는 정렬·간격·토글 동작을 확인했다.
|
||||
Reference in New Issue
Block a user