통수위험 팝업 디자인 보완

This commit is contained in:
kiminchan
2026-06-15 17:34:24 +09:00
parent e47c00f0b6
commit 2ea207a63a
2 changed files with 98 additions and 51 deletions
@@ -57,21 +57,18 @@ const DEFAULT_SETTING_FILTERS: SettingFilters = {
}; };
const TOOLBAR_INPUT_CLASS_NAME = const TOOLBAR_INPUT_CLASS_NAME =
"h-[30px] rounded-none border border-[#8f98a3] bg-white px-2 text-[12px] text-[#1f2937] outline-none"; "h-10 rounded-md border border-slate-300 bg-white px-3 text-[1.05rem] text-slate-700 outline-none";
const TOOLBAR_BUTTON_CLASS_NAME =
"h-[30px] min-w-[44px] rounded-none border border-[#7c5a20] bg-[#ef8d2f] px-3 text-[12px] font-semibold text-white hover:bg-[#df7f24]";
const SECONDARY_BUTTON_CLASS_NAME = const SECONDARY_BUTTON_CLASS_NAME =
"h-[28px] rounded-none border border-[#8f98a3] bg-white px-3 text-[12px] text-[#334155] hover:bg-[#f8fafc]"; "h-10 rounded-md border border-slate-300 bg-white px-5 text-[1.05rem] text-slate-700 hover:bg-slate-100";
const ACTION_BUTTON_CLASS_NAME = const ACTION_BUTTON_CLASS_NAME =
"h-[28px] rounded-[6px] border border-[#2e77bc] bg-[#3f8fd7] px-3 text-[12px] font-semibold text-white hover:bg-[#337ec1]"; "h-10 px-5 !text-[1.05rem]";
const WATER_RISK_PAGE_SIZE = 10; const WATER_RISK_PAGE_SIZE = 10;
const RESULT_TABLE_CONTAINER_CLASS_NAME = const RESULT_TABLE_CONTAINER_CLASS_NAME =
"min-h-0 overflow-hidden rounded-[10px] border border-[#d6e1ee] bg-[linear-gradient(180deg,#ffffff_0%,#f9fbfe_100%)] shadow-[0_6px_16px_rgba(31,59,87,0.06)]"; "min-h-0 overflow-hidden border border-[#dbe2e6] bg-white";
const SETTING_TABLE_CONTAINER_CLASS_NAME = const SETTING_TABLE_CONTAINER_CLASS_NAME =
"min-h-0 overflow-hidden rounded-[10px] border border-[#d6e1ee] bg-[linear-gradient(180deg,#ffffff_0%,#f9fbfe_100%)] shadow-[0_6px_16px_rgba(31,59,87,0.06)]"; "min-h-0 overflow-hidden border border-[#dbe2e6] bg-white";
const postMessageToOpener = (type: string, payload?: Record<string, unknown>) => { const postMessageToOpener = (type: string, payload?: Record<string, unknown>) => {
if (typeof window === "undefined" || !window.opener) return; if (typeof window === "undefined" || !window.opener) return;
@@ -396,28 +393,28 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
}; };
return ( return (
<main className="flex h-screen flex-col overflow-hidden bg-[linear-gradient(180deg,#f7f9fc_0%,#eef4fa_100%)] text-[#202a36]"> <main className="flex h-screen flex-col overflow-hidden bg-white text-slate-800">
<header className="flex h-[46px] items-center border-b border-[#e2ebf5] bg-[linear-gradient(180deg,#ffffff_0%,#f3f8fd_100%)] px-[18px]"> <header className="flex min-h-[44px] items-center border-b border-[#dbe2e6] bg-primary px-5 py-3">
{activeView === "setting" ? ( {activeView === "setting" ? (
<button <button
type="button" type="button"
className="mr-3 text-[12px] font-semibold text-[#51657a] hover:text-[#1f2937]" className="mr-3 text-[1.05rem] font-medium text-white/90 hover:text-white"
onClick={handleReturnToResultView} onClick={handleReturnToResultView}
> >
← 결과조회 ← 결과조회
</button> </button>
) : null} ) : null}
<h1 className="text-[1.1rem] font-semibold tracking-[-0.01em] text-[#1f3b57]"> <h1 className="text-[1.45rem] font-semibold text-white">
{activeView === "result" ? "통수위험분석" : "통수위험분석 설정"} {activeView === "result" ? "통수위험분석" : "통수위험분석 설정"}
</h1> </h1>
</header> </header>
<section className="flex-1 overflow-hidden px-[12px] pb-[12px] pt-[10px]"> <section className="flex-1 overflow-y-auto p-4">
{activeView === "result" ? ( {activeView === "result" ? (
<section className="flex h-full min-h-0 flex-col gap-[8px]"> <section className="flex h-full min-h-0 flex-col gap-3">
<div className="overflow-x-auto"> <div className="grid grid-cols-1 gap-3 border-b border-slate-200 bg-slate-50 pb-4 md:grid-cols-[160px_140px_140px_140px_180px_120px_auto] md:items-end">
<div className="flex min-w-max items-center gap-[12px] rounded-[10px] border border-[#d6e1ee] bg-[linear-gradient(180deg,#ffffff_0%,#f9fbfe_100%)] px-[10px] py-[8px] shadow-[0_6px_16px_rgba(31,59,87,0.06)]"> <label className="block">
<div className="flex flex-1 items-center gap-[4px]"> <div className="mb-1 text-[1.05rem] font-medium text-slate-700">기준일자</div>
<input <input
type="date" type="date"
value={draftResultFilters.analysisDate} value={draftResultFilters.analysisDate}
@@ -428,8 +425,11 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="년월일" aria-label="년월일"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[120px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
/> />
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">기준시간</div>
<input <input
type="time" type="time"
value={draftResultFilters.analysisTime} value={draftResultFilters.analysisTime}
@@ -440,8 +440,11 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="시간" aria-label="시간"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[100px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
/> />
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">시도</div>
<select <select
value={draftResultFilters.sidoName} value={draftResultFilters.sidoName}
onChange={(event) => onChange={(event) =>
@@ -452,7 +455,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="시도" aria-label="시도"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[94px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
{WATER_RISK_SIDO_OPTIONS.map((option) => ( {WATER_RISK_SIDO_OPTIONS.map((option) => (
<option key={option} value={option}> <option key={option} value={option}>
@@ -460,6 +463,9 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">시군구</div>
<select <select
value={draftResultFilters.sggName} value={draftResultFilters.sggName}
onChange={(event) => onChange={(event) =>
@@ -469,7 +475,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="시군구" aria-label="시군구"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[94px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
{resultSggOptions.map((option) => ( {resultSggOptions.map((option) => (
<option key={option} value={option}> <option key={option} value={option}>
@@ -477,6 +483,9 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">중점관리지역</div>
<select <select
value={draftResultFilters.areaId} value={draftResultFilters.areaId}
onChange={(event) => onChange={(event) =>
@@ -486,7 +495,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="중점관리지역" aria-label="중점관리지역"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[120px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
<option value="ALL">중점관리지역</option> <option value="ALL">중점관리지역</option>
{resultAreaOptions.map((option) => ( {resultAreaOptions.map((option) => (
@@ -495,6 +504,9 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">위험상태</div>
<select <select
value={draftResultFilters.riskStatus} value={draftResultFilters.riskStatus}
onChange={(event) => onChange={(event) =>
@@ -504,18 +516,19 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="위험상태" aria-label="위험상태"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[74px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
<option value="ALL">위험</option> <option value="ALL">전체</option>
<option value="DANGER">위험</option> <option value="DANGER">위험</option>
<option value="NORMAL">정상</option> <option value="NORMAL">정상</option>
</select> </select>
</div> </label>
<div className="ml-auto flex items-center gap-[4px]"> <div className="flex flex-wrap items-end justify-end gap-2">
<Button <Button
type="button" type="button"
size="sm" size="sm"
className="h-[30px] min-w-[48px] rounded-[4px] bg-[#2f7ec4] px-[10px] text-[12px] font-semibold text-white hover:bg-[#266fad]" color="primary"
className="h-10 px-5 !text-[1.05rem]"
onClick={handleApplyResultFilters} onClick={handleApplyResultFilters}
> >
조회 조회
@@ -523,19 +536,25 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
<Button <Button
type="button" type="button"
size="sm" size="sm"
className="h-[30px] min-w-[48px] rounded-[4px] bg-[#ef8d2f] px-[10px] text-[12px] font-semibold text-white hover:bg-[#df7f24]" color="white"
className={SECONDARY_BUTTON_CLASS_NAME}
onClick={handleOpenSettingView} onClick={handleOpenSettingView}
> >
설정 설정
</Button> </Button>
</div>
</div> </div>
</div> </div>
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
통수위험 분석 결과 {visibleResultRows.length.toLocaleString("ko-KR")}건
</h3>
</div>
<div className={RESULT_TABLE_CONTAINER_CLASS_NAME}> <div className={RESULT_TABLE_CONTAINER_CLASS_NAME}>
<div className="overflow-x-auto overflow-y-hidden"> <div className="overflow-x-auto overflow-y-hidden">
<table <table
className="border-collapse text-[12px]" className="border-collapse text-[1.05rem]"
style={{ minWidth: `${resultTableMinWidth}px`, width: "100%" }} style={{ minWidth: `${resultTableMinWidth}px`, width: "100%" }}
> >
<thead> <thead>
@@ -620,10 +639,10 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
) : null} ) : null}
</section> </section>
) : ( ) : (
<section className="flex h-full min-h-0 flex-col gap-2"> <section className="flex h-full min-h-0 flex-col gap-3">
<div className="overflow-x-auto"> <div className="grid grid-cols-1 gap-3 border-b border-slate-200 bg-slate-50 pb-4 md:grid-cols-[160px_160px_220px_auto] md:items-end">
<div className="flex min-w-max items-center gap-[12px] rounded-[10px] border border-[#d6e1ee] bg-[linear-gradient(180deg,#ffffff_0%,#f9fbfe_100%)] px-[8px] py-[8px] shadow-[0_6px_16px_rgba(31,59,87,0.06)]"> <label className="block">
<div className="flex flex-1 items-center gap-[4px]"> <div className="mb-1 text-[1.05rem] font-medium text-slate-700">시도</div>
<select <select
value={draftSettingFilters.sidoName} value={draftSettingFilters.sidoName}
onChange={(event) => onChange={(event) =>
@@ -634,7 +653,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="시도" aria-label="시도"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[94px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
{WATER_RISK_SIDO_OPTIONS.map((option) => ( {WATER_RISK_SIDO_OPTIONS.map((option) => (
<option key={option} value={option}> <option key={option} value={option}>
@@ -642,6 +661,9 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">시군구</div>
<select <select
value={draftSettingFilters.sggName} value={draftSettingFilters.sggName}
onChange={(event) => onChange={(event) =>
@@ -651,7 +673,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="시군구" aria-label="시군구"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[94px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
{settingSggOptions.map((option) => ( {settingSggOptions.map((option) => (
<option key={option} value={option}> <option key={option} value={option}>
@@ -659,6 +681,9 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</label>
<label className="block">
<div className="mb-1 text-[1.05rem] font-medium text-slate-700">중점관리지역</div>
<select <select
value={draftSettingFilters.areaId} value={draftSettingFilters.areaId}
onChange={(event) => onChange={(event) =>
@@ -668,7 +693,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
})) }))
} }
aria-label="중점관리지역" aria-label="중점관리지역"
className={`${TOOLBAR_INPUT_CLASS_NAME} w-[120px]`} className={`${TOOLBAR_INPUT_CLASS_NAME} w-full`}
> >
<option value="ALL">중점관리지역</option> <option value="ALL">중점관리지역</option>
{settingAreaOptions.map((option) => ( {settingAreaOptions.map((option) => (
@@ -677,26 +702,32 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</option> </option>
))} ))}
</select> </select>
</div> </label>
<div className="ml-auto flex items-center gap-[4px]"> <div className="flex flex-wrap items-end justify-end gap-2">
<Button <Button
type="button" type="button"
size="sm" size="sm"
className="h-[30px] min-w-[48px] rounded-[4px] bg-[#2f7ec4] px-[10px] text-[12px] font-semibold text-white hover:bg-[#266fad]" color="primary"
className="h-10 px-5 !text-[1.05rem]"
onClick={handleApplySettingFilters} onClick={handleApplySettingFilters}
> >
조회 조회
</Button> </Button>
</div>
</div> </div>
</div> </div>
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
통수위험 설정 현황 {visibleSettingRows.length.toLocaleString("ko-KR")}건
</h3>
</div>
<div <div
className={`${SETTING_TABLE_CONTAINER_CLASS_NAME} ${showSettingEditor ? "flex-[0_0_44%]" : ""}`} className={`${SETTING_TABLE_CONTAINER_CLASS_NAME} ${showSettingEditor ? "flex-[0_0_44%]" : ""}`}
> >
<div className="overflow-x-auto overflow-y-hidden"> <div className="overflow-x-auto overflow-y-hidden">
<table <table
className="border-collapse text-[12px]" className="border-collapse text-[1.05rem]"
style={{ minWidth: `${settingTableMinWidth}px`, width: "100%" }} style={{ minWidth: `${settingTableMinWidth}px`, width: "100%" }}
> >
<thead className="bg-[#eaf3fb] text-[#647784]"> <thead className="bg-[#eaf3fb] text-[#647784]">
@@ -754,10 +785,10 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
) : null} ) : null}
{showSettingEditor ? ( {showSettingEditor ? (
<div className="min-h-0 flex-1 overflow-hidden rounded-[10px] border border-[#d6e1ee] bg-[linear-gradient(180deg,#ffffff_0%,#f9fbfe_100%)] shadow-[0_6px_16px_rgba(31,59,87,0.06)]"> <div className="min-h-0 flex-1 overflow-hidden border border-[#dbe2e6] bg-white">
<div className="flex h-full min-h-0 flex-col"> <div className="flex h-full min-h-0 flex-col">
<div className="flex items-center justify-between border-b border-[#e2ebf5] px-3 py-2"> <div className="flex items-center justify-between border-b border-slate-200 bg-slate-50 px-4 py-3">
<div className="text-[12px] font-semibold text-[#1f3b57]"> <div className="text-[1.05rem] font-medium text-slate-700">
설정 편집 대상: {currentSettingAreaName || "선택 전"} 설정 편집 대상: {currentSettingAreaName || "선택 전"}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -765,7 +796,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
type="button" type="button"
size="sm" size="sm"
color="white" color="white"
className="h-[28px] rounded-[4px] border border-[#cad7e6] bg-white px-[10px] text-[12px] text-[#43566b] hover:bg-[#f8fbff]" className="h-9 rounded-md border border-slate-300 bg-white px-4 text-[1.05rem] text-slate-700 hover:bg-slate-100"
onClick={handleStopSettingEdit} onClick={handleStopSettingEdit}
> >
편집 종료 편집 종료
@@ -774,7 +805,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
type="button" type="button"
size="sm" size="sm"
color="white" color="white"
className="h-[28px] rounded-[4px] border border-[#cad7e6] bg-white px-[10px] text-[12px] text-[#43566b] hover:bg-[#f8fbff]" className="h-9 rounded-md border border-slate-300 bg-white px-4 text-[1.05rem] text-slate-700 hover:bg-slate-100"
onClick={handleClearStagedPipes} onClick={handleClearStagedPipes}
disabled={snapshot.stagedPipes.length === 0} disabled={snapshot.stagedPipes.length === 0}
> >
@@ -783,6 +814,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
<Button <Button
type="button" type="button"
size="sm" size="sm"
color="primary"
className={ACTION_BUTTON_CLASS_NAME} className={ACTION_BUTTON_CLASS_NAME}
onClick={handlePreviewSave} onClick={handlePreviewSave}
> >
@@ -792,7 +824,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
</div> </div>
<div className="min-h-0 flex-1 overflow-auto"> <div className="min-h-0 flex-1 overflow-auto">
<table className="w-full border-collapse text-[12px]"> <table className="w-full border-collapse text-[1.05rem]">
<thead className="bg-[#e1ebf5] text-[#24364d]"> <thead className="bg-[#e1ebf5] text-[#24364d]">
<tr> <tr>
<th className="border border-[#dbe4ec] px-2 py-2">순번</th> <th className="border border-[#dbe4ec] px-2 py-2">순번</th>
@@ -832,7 +864,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
type="button" type="button"
size="sm" size="sm"
color="white" color="white"
className="h-[28px] rounded-[4px] border border-[#cad7e6] bg-white px-[10px] text-[12px] text-[#43566b] hover:bg-[#f8fbff]" className="h-9 rounded-md border border-slate-300 bg-white px-4 text-[1.05rem] text-slate-700 hover:bg-slate-100"
onClick={() => handleMoveStagedPipe(pipe.pipeId, "UP")} onClick={() => handleMoveStagedPipe(pipe.pipeId, "UP")}
disabled={index === 0} disabled={index === 0}
> >
@@ -842,7 +874,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
type="button" type="button"
size="sm" size="sm"
color="white" color="white"
className="h-[28px] rounded-[4px] border border-[#cad7e6] bg-white px-[10px] text-[12px] text-[#43566b] hover:bg-[#f8fbff]" className="h-9 rounded-md border border-slate-300 bg-white px-4 text-[1.05rem] text-slate-700 hover:bg-slate-100"
onClick={() => handleMoveStagedPipe(pipe.pipeId, "DOWN")} onClick={() => handleMoveStagedPipe(pipe.pipeId, "DOWN")}
disabled={index === snapshot.stagedPipes.length - 1} disabled={index === snapshot.stagedPipes.length - 1}
> >
@@ -852,7 +884,7 @@ export default function WaterRiskPopupPage(_props: WindowPopupContentProps) {
type="button" type="button"
size="sm" size="sm"
color="white" color="white"
className="h-[28px] rounded-none border border-[#e7b7b7] bg-white px-3 text-[12px] text-[#c62828] hover:bg-[#fff8f8]" className="h-9 rounded-md border border-[#e7b7b7] bg-white px-4 text-[1.05rem] text-[#c62828] hover:bg-[#fff8f8]"
onClick={() => handleRemoveStagedPipe(pipe.pipeId)} onClick={() => handleRemoveStagedPipe(pipe.pipeId)}
> >
삭제 삭제
@@ -95,6 +95,21 @@
- 남은 메모 - 남은 메모
- 실제 운영에서 요구되는 카드 고정 규칙과 사용성은 브라우저 수동 검증에서 한 번 더 확정할 필요가 있다. - 실제 운영에서 요구되는 카드 고정 규칙과 사용성은 브라우저 수동 검증에서 한 번 더 확정할 필요가 있다.
### 4.6 2026-06-15 통수위험 팝업 디자인 톤 재정렬
- 반영 파일
- `FE_APP_ROOT/app/(map-layout)/map/components/waterRisk/WaterRiskPopupPage.tsx`
- 배경
- 사용자 피드백 기준으로 현재 `통수위험분석` 팝업은 `관로분석`, `노후관로` 계열과 비교해 별도 그라데이션/카드/버튼 톤이 강해 혼자 튀는 상태로 보였다.
- 이번 라운드에서는 기능 흐름은 유지하고, 시각 언어만 기존 지도형 팝업 계열과 같은 방향으로 다시 맞추는 것을 목표로 했다.
- 구현 내용
- 상단 헤더를 `bg-primary` + 흰색 제목 구조로 바꿔 `관로분석`, `노후관로` 팝업과 같은 첫인상을 맞췄다.
- 본문 배경을 흰색으로 단순화하고, 조회조건 영역을 `slate-50` 기반 필터 바 형태로 바꿨다.
- 결과/설정 화면 모두에 `card-header` 스타일의 제목 줄을 추가해 기존 팝업의 표 제목 리듬과 맞췄다.
- 버튼 높이, 입력 높이, 테이블 외곽선, 편집 영역 상단 바를 기존 팝업 계열과 가까운 톤으로 조정했다.
- 남은 메모
- 현재는 `노후관로`/`관로분석` 계열에 시각 톤을 맞춘 1차 정리이며, 실제 사용자 체감 기준에서 간격이나 글자 크기 보정이 더 필요하면 후속 유지보수로 미세조정할 수 있다.
## 5. 기능별 현재 상태 ## 5. 기능별 현재 상태
### 5.1 결과 조회 ### 5.1 결과 조회