(null);
+
+ // ✅ selected 계산 안정화
+ const selected = useMemo(() => {
+ if (!rows.length) return null;
+ const found = rows.find((r) => r.id === selectedId);
+ return found ?? rows[0];
+ }, [rows, selectedId]);
+
+ // ✅ rows가 바뀌었는데 selectedId가 null이면 자동 첫번째 선택
+ useEffect(() => {
+ const first = rows[0];
+ if (!first) return; // ✅ rows가 비어있으면 종료 (TS + 런타임 안전)
+
+ if (selectedId == null) setSelectedId(first.id);
+ }, [rows, selectedId]);
+
+ // ✅ 상단 2행(요구시기/요구수량/사용용도/희망단가) - TS 안전하게 object로 구성
+ const topFields: TopField[] = useMemo(() => {
+ if (!selected) return [];
+ return [
+ { label: "요구시기", value: selected.detail.reqDate, required: true },
+ { label: "요구수량(㎡/d)", value: selected.detail.reqQty },
+ { label: "사용용도", value: selected.detail.usePurpose },
+ { label: "희망단가(원)", value: selected.detail.price },
+ ];
+ }, [selected]);
+
+ // ✅ 수질 항목 - TS 안전
+ const waterFields: PairField[] = useMemo(() => {
+ if (!selected) return [];
+ const w = selected.detail.water;
+ return [
+ { label: "총대장균군수(개/100mℓ)", value: w.coliform },
+ { label: "결합잔류염소(mg/L)", value: "-" },
+ { label: "탁도(NTU)", value: w.turbidity },
+
+ { label: "생물화학적산소요구량(BOD)(mg/L)", value: w.bdo },
+ { label: "냄새", value: w.odor },
+ { label: "색도(도)", value: w.color },
+
+ { label: "총질소(T-N)(mg/L)", value: w.tn },
+ { label: "총인(T-P)(mg/L)", value: w.tp },
+ { label: "수소이온농도(pH)", value: w.ph },
+
+ { label: "염화물(mgCL/L)", value: w.cl },
+ { label: "전기전도도(µs/cm)", value: w.conductivity },
+ { label: "비고", value: w.note },
+ ];
+ }, [selected]);
+
+ const onSelectRow = (id: number) => {
+ setSelectedId(id);
+
+ // ✅ “행 클릭 → 아래 상세로 보여짐” 체감 확실히: 상세영역으로 이동
+ // (사용자가 이미 아래를 보고 있다면 거의 움직이지 않음)
+ requestAnimationFrame(() => {
+ detailRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
+ });
+ };
+
+ return (
+
+ {/* 서브 타이틀 + 브레드크럼 */}
+
+
+ {/* 컨텐츠 영역 */}
+
+ {/* 리스트 테이블 */}
+
+ 수요정보 신청현황
+
+
+
+
+
+ | NO. |
+ 시도 |
+ 시군구 |
+ 회사명 |
+ 공장주소 |
+ 전화번호 |
+ 신청일자 |
+ 진행상태 |
+
+
+
+
+ {rows.length === 0 ? (
+
+ |
+ 조회된 신청내역이 없습니다.
+ |
+
+ ) : (
+ rows.map((r) => {
+ const active = r.id === selected?.id;
+ return (
+ onSelectRow(r.id)}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === " ") onSelectRow(r.id);
+ }}
+ className={[
+ "border-t border-neutral-200 outline-none",
+ "cursor-pointer",
+ active ? "bg-slate-50" : "hover:bg-slate-50",
+ "focus-visible:ring-2 focus-visible:ring-slate-300",
+ ].join(" ")}
+ aria-selected={active}
+ >
+ | {r.id} |
+ {r.sido} |
+ {r.sigungu} |
+ {r.company} |
+ {r.address} |
+ {r.phone} |
+ {r.date} |
+
+
+ |
+
+ );
+ })
+ )}
+
+
+
+
+
+ {/* 상세현황 */}
+
+ 수요신청 상세현황
+
+ {!selected ? (
+
+ 상세 정보를 표시할 신청건이 없습니다.
+
+ ) : (
+
+
+ 요구수량
+
+
+
+ {/* 상단 2행 */}
+ {topFields.map((f) => (
+
+
+ {f.label}
+ {f.required ? * : null}
+
+
+ {f.value}
+
+
+ ))}
+
+ {/* 수질 */}
+
+ 요구수질
+
+
+ {waterFields.map((f) => (
+
+
+ {f.label}
+
+
+ {f.value}
+
+
+ ))}
+
+ {/* 공급처 후보지 */}
+
+ 공급처 후보지
+
+
+ {selected.detail.candidates.map((v, i) => (
+
+
+ 후보지{i + 1}
+
+
+ {v}
+
+
+ ))}
+
+
+ )}
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/layout.tsx b/apps/dm_new/app/(with-layout)/example/layout.tsx
new file mode 100644
index 000000000..f117d6792
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/layout.tsx
@@ -0,0 +1,11 @@
+import type { ReactNode } from "react";
+import Lnb from "@/components/Lnb";
+
+export default function BusinessLayout({ children }: { children: ReactNode }) {
+ return (
+
+
+ {children}
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/rain/suwon/page.tsx b/apps/dm_new/app/(with-layout)/example/rain/suwon/page.tsx
new file mode 100644
index 000000000..17b31d9b2
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/rain/suwon/page.tsx
@@ -0,0 +1,93 @@
+// apps/dm/app/(landing)/reuse/business/rain/suwon/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 경기도 수원시 빗물이용과 중수도
+
+
+
+
+
+ {/* 사업 방식 */}
+
+ 사업 방식
+
+ (빗물) 월드컵경기장 등 4개소에 노면 빗물분사시스템 및 빗물 공급기를 설치하여 혹서기 도시 열섬효과 및 도로 비산먼지 저감
+ ※ 시설 가동중 도로 노면 온도의 7.2 ~ 26.3℃ 감소 효과 확인(‘21.7월, 수원시청).
+ 다만, 가뭄기나 강우량이 적을 경우 빗물을 원활히 공급하기 다소 곤란
+ - (중수도) 수원시청, 장안구청, 월드컵경기장에 빗물 연계 중수도를 화장실·조경용수 등으로 사용하여 수도요금 절감(연 7백~30백만원)
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/bolyeong/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/bolyeong/page.tsx
new file mode 100644
index 000000000..fe2331e19
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/bolyeong/page.tsx
@@ -0,0 +1,111 @@
+// apps/dm/app/(landing)/reuse/business/sewage/bolyeong/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 충남 보령 하수재이용
+ : 보령·신보령화력발전소에 하루 1만톤의 탈황용수 공급을 위해 보령하수처리시설의 하수처리수 재이용 사업 추진
+
+
+
+
+
+ {/* 사업 방식 */}
+
+ 사업 방식
+
+ 2017년 한국환경공단과 사업대행 위 · 수탁 협약 체결
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 처리공정 : 전처리 UF + 후처리 RO
+ 시설용량 : 1만m³/일
+ 관로 : 8.7km
+ 사업비 : 315억원
+ 위치: 충청남도 보령시 대청방조제로 322 일원
+
+
+
+
+
+ {/* 특이사항 */}
+
+ 특이사항
+
+ 국내 유일 하수재이용 공업용수 공급 재정사업으로 2016년 충남 서부권 가뭄 시 지역사회 기여 차원에서 기관간 MOU(환경부, 충청남도, 보령시, 한국중부발전㈜)를 바탕으로 추진 되어 경제성보다 공익성을 바탕으로
+ 국가전력 기반시설의 안정적 운영 도모
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/cheongju/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/cheongju/page.tsx
new file mode 100644
index 000000000..5f2e1928f
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/cheongju/page.tsx
@@ -0,0 +1,94 @@
+// apps/dm/app/(landing)/reuse/business/sewage/cheongju/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 청주시 하수 재이용 시설
+
+
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 청주시 하수처리수 재이용 민간투자사업(BTO)
+ 공급량 : 35,000㎥/일
+ 공급관로 : 8.3㎞
+ 사업비 : 622억원
+ 수요처 : SK하이닉스 등 일반산업단지
+ 지역 (위치) : 충청북도 청주시 흥덕구 가락리 135-9번지 일원
+ 처리용량 : 35.000(m³/일)
+ 적용기술 : 분리막 (UF : 전처리), (RO : 주처리)
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/guri/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/guri/page.tsx
new file mode 100644
index 000000000..46796d714
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/guri/page.tsx
@@ -0,0 +1,171 @@
+// apps/dm/app/(landing)/reuse/business/sewage/guri/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 수원시 황수원시 황구지천 하수처리수 재이용사업
+
+
+
+
+
+ {/* 사업목적 */}
+
+ 사업목적
+
+ 황구지천 공공하수처리시설 하수처리수 재이용사업으로 향후 호매실천 및 금곡천 건천화 방지로 주민들에게 친수 공간 제공 및 하천 생태계 보전
+
+
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 총사업비 : 110억원
+ 위 치 : 수원시 권선구 호매실천, 금곡천
+ 관 로 : 3.9km
+ 공 급 량 : 25,000㎥/일(하수처리시설 용량: 45,000㎥/일)
+
+
+
+
+
+ {/* 공급계획 */}
+
+ 공급계획
+ {/* 데이터 테이블 */}
+
+
+
+
+ {/* 구분 */}
+ |
+ 구분
+ |
+
+ {/* 공급량 */}
+
+ 공급량
+ |
+
+ {/* 비고 */}
+
+ 비고
+ |
+
+
+
+
+
+ {/* 좌측 병합 */}
+ |
+ 하천 등 유지용수
+ |
+
+
+ 12,500m³/일
+ |
+
+
+ 호매실천 공급
+ |
+
+
+
+ |
+ 6,250m³/일
+ |
+
+
+ 금곡천1 공급
+ |
+
+
+
+ |
+ 6,250m³/일
+ |
+
+
+ 금곡천2 공급
+ |
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/hwanggu/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/hwanggu/page.tsx
new file mode 100644
index 000000000..36893ee7a
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/hwanggu/page.tsx
@@ -0,0 +1,171 @@
+// apps/dm/app/(landing)/reuse/business/sewage/hwanggu/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 수원시 황수원시 황구지천 하수처리수 재이용사업
+
+
+
+
+
+ {/* 사업목적 */}
+
+ 사업목적
+
+ 황구지천 공공하수처리시설 하수처리수 재이용사업으로 향후 호매실천 및 금곡천 건천화 방지로 주민들에게 친수 공간 제공 및 하천 생태계 보전
+
+
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 총사업비 : 110억원
+ 위 치 : 수원시 권선구 호매실천, 금곡천
+ 관 로 : 3.9km
+ 공 급 량 : 25,000㎥/일(하수처리시설 용량: 45,000㎥/일)
+
+
+
+
+
+ {/* 공급계획 */}
+
+ 공급계획
+ {/* 데이터 테이블 */}
+
+
+
+
+ {/* 구분 */}
+ |
+ 구분
+ |
+
+ {/* 공급량 */}
+
+ 공급량
+ |
+
+ {/* 비고 */}
+
+ 비고
+ |
+
+
+
+
+
+ {/* 좌측 병합 */}
+ |
+ 하천 등 유지용수
+ |
+
+
+ 12,500m³/일
+ |
+
+
+ 호매실천 공급
+ |
+
+
+
+ |
+ 6,250m³/일
+ |
+
+
+ 금곡천1 공급
+ |
+
+
+
+ |
+ 6,250m³/일
+ |
+
+
+ 금곡천2 공급
+ |
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/paju/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/paju/page.tsx
new file mode 100644
index 000000000..27b94afda
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/paju/page.tsx
@@ -0,0 +1,112 @@
+// apps/dm/app/(landing)/reuse/business/sewage/paju/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 경기도 파주시 하수재이용
+ : 운정·금촌하수처리시설의 하수처리수를 막공법(U/F, R/O)으로 재처리하여 파주 LCD 산업단지내 3개 업체*에 공업용수 공급
+ *LG디스플레이(P10공장), 희성전자, 엔비텍 등
+
+
+
+
+
+ {/* 사업 배경 및 목적 */}
+
+ 사업 배경 및 목적
+
+ 민간투자사업(시행사 : 파주그린허브(주), 운영사 : 테크로스)
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 처리공정 : 전처리 UF + 후처리 RO
+ 공급량 : 4만m³/일
+ 관로 : 13.6km
+ 사업비 : 651억원
+ 위치 : 경기도 파주시 금촌동 714번지 일원
+ 시설용량 : 41,20m³/일
+
+
+
+
+
+ {/* 특이사항 */}
+
+ 특이사항
+
+ 하수처리수 재이용시설 자체 농축폐수 처리공정 개발 및 적용 성공사례
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/example/sewage/yeosu/page.tsx b/apps/dm_new/app/(with-layout)/example/sewage/yeosu/page.tsx
new file mode 100644
index 000000000..a96260608
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/example/sewage/yeosu/page.tsx
@@ -0,0 +1,101 @@
+// apps/dm/app/(landing)/reuse/business/sewage/yeosu/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+import CaseImageSlider from "@/components/CaseImageSlider";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 슬라이드 이미지 영역 */}
+
+
+ {/* 사업명 */}
+
+ 사업명
+
+ 여수시 하수처리수 재이용 민간 투자사업(BTO)
+
+
+
+
+
+ {/* 사업 목적 */}
+
+ 사업 목적
+
+ 수요자가 원하는 양질의 공업용수를 저렴하게 곰급하여 한정된 수자원의 효율적 이용 및 지역적 물 부족 해소, 하수재이용을 통한 오염총량 저감 및 방류수역 수질개선
+
+
+
+ {/* 사업 주요 내용 */}
+
+ 사업 주요 내용
+
+ 총사업비 : GS칼텍스, YNCC(주) 등 750억원
+ 시행사 : 여수그린허브(주)
+ 운영사 : 테크로스
+ 위치: 여수시 신월로 2844일원 (여수 하수처리시설 부지 내)
+ 처리공법 : 전처리시설(MF) + 주처리시설(RO)
+ 시설용량 및 공급량 : 5만m³/일
+ 관로 : 18.6km
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/intro/greywater/page.tsx b/apps/dm_new/app/(with-layout)/intro/greywater/page.tsx
new file mode 100644
index 000000000..54f4ef682
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/intro/greywater/page.tsx
@@ -0,0 +1,86 @@
+// apps/dm/app/(landing)/reuse/intro/greywater/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 1) 중수 재이용 소개 */}
+
+
+
+
+ {/* 2) 중수도 설치 의무 대상 */}
+
+
+
+
+ {/* 3) 중수도 시설기준 및 관리기준 */}
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/intro/law/page.tsx b/apps/dm_new/app/(with-layout)/intro/law/page.tsx
new file mode 100644
index 000000000..32728806b
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/intro/law/page.tsx
@@ -0,0 +1,122 @@
+// apps/dm/app/(landing)/reuse/intro/law/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function WaterReuseLawPage() {
+ return (
+
+
+
+
+
+ {/* 1) 법제도/계획 수립 타임라인 */}
+
+
+
+
+ {/* 2) 제2차 계획 대비 실적 현황 (2컬럼) */}
+
+
+
+
+ {/* 3) 국내 관련 현황 */}
+
+
+
+
+ {/* 4) 정책 변천 추이 */}
+
+
+
+
+ {/* 5) 타 법령과의 관계도 */}
+
+
+
+
+ {/* 6) 국내 연계 현황 */}
+
+ 국내 연계 현황
+
+
+
주요 국가계획의 정책방향과 연계한 물 재이용 정책 필요
+
국가 상위계획의 정책 방향이 기후위기 대응 등 수자원의 공급 안전성을 위한 물 재이용 활성화로 정책 실효성 제고 필요
+ • 물관리 계획(국가수도기본계획, 국가 및 유역하수도종합계획, 하천유역수자원관리계획 등)과의 연계성 확보 → 통합적인 관점에서 물이용 체계 구축 필요
+
+
+
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/intro/layout.tsx b/apps/dm_new/app/(with-layout)/intro/layout.tsx
new file mode 100644
index 000000000..91e9e2e54
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/intro/layout.tsx
@@ -0,0 +1,11 @@
+import type { ReactNode } from "react";
+import Lnb from "@/components/Lnb";
+
+export default function IntroLayout({ children }: { children: ReactNode }) {
+ return (
+
+
+ {children}
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/intro/rain/page.tsx b/apps/dm_new/app/(with-layout)/intro/rain/page.tsx
new file mode 100644
index 000000000..72f36b797
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/intro/rain/page.tsx
@@ -0,0 +1,76 @@
+// apps/dm/app/(landing)/reuse/intro/law/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function RainwaterReusePage() {
+ return (
+
+
+
+
+
+ {/* 1) 빗물 재이용 소개 */}
+
+
+
+
+ {/* 2) 빗물이용시설 설치 관리 법적 의무 대상 */}
+
+ 빗물이용시설 설치 관리 법적 의무 대상
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/intro/sewage/page.tsx b/apps/dm_new/app/(with-layout)/intro/sewage/page.tsx
new file mode 100644
index 000000000..c6e355ed9
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/intro/sewage/page.tsx
@@ -0,0 +1,76 @@
+// apps/dm/app/(landing)/reuse/intro/treated/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function TreatedWaterPage() {
+ return (
+
+
+
+
+
+ {/* 1) 하수처리수 */}
+
+
+
+
+ {/* 2) 하수처리수 재이용시설 의무 대상 */}
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/layout.tsx b/apps/dm_new/app/(with-layout)/layout.tsx
new file mode 100644
index 000000000..f3c5088e1
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/layout.tsx
@@ -0,0 +1,13 @@
+// app/(with-layout)/layout.tsx
+import "../reuse.module.css";
+import type { ReactNode } from "react";
+import TopNav from "@/components/TopNav";
+
+export default function ReuseLandingLayout({ children }: { children: React.ReactNode }) {
+ return (
+ <>
+
+ {children}
{/* TopNav 높이만큼 */}
+ >
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/status/greywater/page.tsx b/apps/dm_new/app/(with-layout)/status/greywater/page.tsx
new file mode 100644
index 000000000..37d958045
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/status/greywater/page.tsx
@@ -0,0 +1,96 @@
+// apps/dm/app/(landing)/reuse/cases/greywater/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 1) 전체 중수도 설치 및 이용 현황 (공장 및 발전시설 제외) */}
+
+ 전체 중수도 설치 및 이용 현황 (공장 및 발전시설 제외)
+
+
+
+
+
+ {/* 2) 중수공장 및 발전시설 내 중수도 설치 및 이용 현황 */}
+
+ 공장 및 발전시설 내 중수도 설치 및 이용 현황
+
+
+
+
+
+ {/* 3) 중수도 건축물별 이용량 현황 */}
+
+
+
+
+ {/* 4) 중수도 용도별 이용량 현황 */}
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/status/layout.tsx b/apps/dm_new/app/(with-layout)/status/layout.tsx
new file mode 100644
index 000000000..614eb47ed
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/status/layout.tsx
@@ -0,0 +1,11 @@
+import type { ReactNode } from "react";
+import Lnb from "@/components/Lnb";
+
+export default function CasesLayout({ children }: { children: ReactNode }) {
+ return (
+
+
+ {children}
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/status/rain/page.tsx b/apps/dm_new/app/(with-layout)/status/rain/page.tsx
new file mode 100644
index 000000000..810053f52
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/status/rain/page.tsx
@@ -0,0 +1,86 @@
+// apps/dm/app/(landing)/reuse/cases/rain/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 1) 빗물이용시설의 건축물별 빗물이용량 현황 */}
+
+ 빗물이용시설의 건축물별 빗물이용량 현황
+
+
+
+
+
+ {/* 2) 빗물이용시설의 용도별 분포 (2023년 기준) */}
+
+ 빗물이용시설의 용도별 분포 (2023년 기준)
+
+
+
+
+
+ {/* 3) 빗물이용시설의 용도별 빗물이용량 현황 */}
+
+ 빗물이용시설의 용도별 빗물이용량 현황
+
+
+
+ );
+}
diff --git a/apps/dm_new/app/(with-layout)/status/sewage/page.tsx b/apps/dm_new/app/(with-layout)/status/sewage/page.tsx
new file mode 100644
index 000000000..21b3a5bcf
--- /dev/null
+++ b/apps/dm_new/app/(with-layout)/status/sewage/page.tsx
@@ -0,0 +1,96 @@
+// apps/dm/app/(landing)/reuse/cases/treated/page.tsx
+"use client";
+
+import SubPageHeader from "@/components/SubPageHeader";
+
+function SectionTitle({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
{children}
+
+ );
+}
+
+type HrProps = {
+ className?: string;
+};
+
+function Hr({ className = "" }: HrProps) {
+ return ;
+}
+
+type ImgCardProps = {
+ src: string;
+ alt: string;
+};
+
+function ImgCard({ src, alt }: ImgCardProps) {
+ return (
+
+

+
+ );
+}
+
+export default function GreywaterPage() {
+ return (
+
+
+
+
+
+ {/* 1) 연도별 하수처리수 재이용 현황 */}
+
+
+
+
+ {/* 2) 용도별 하수처리수 재이용 현황 */}
+
+
+
+
+ {/* 3) 하수처리시설 설치 및 이용 현황 */}
+
+
+
+
+ {/* 4) 시도별 하수처리수 재이용 현황 */}
+
+
+ );
+}
diff --git a/apps/dm_new/app/layout.tsx b/apps/dm_new/app/layout.tsx
index 7224c9dc2..58eec5936 100644
--- a/apps/dm_new/app/layout.tsx
+++ b/apps/dm_new/app/layout.tsx
@@ -2,7 +2,7 @@
import "./globals.css";
import { setCookie } from "../src/shared/lib";
-setCookie("site-id-key", process.env.NEXT_PUBLIC_SITE_ID || "DM");
+setCookie("site-id-key", process.env.NEXT_PUBLIC_SITE_ID || "DN");
export default function RootLayout({
children,
diff --git a/apps/dm_new/app/main/SideIndicator.tsx b/apps/dm_new/app/main/SideIndicator.tsx
new file mode 100644
index 000000000..8f4cea164
--- /dev/null
+++ b/apps/dm_new/app/main/SideIndicator.tsx
@@ -0,0 +1,99 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import styles from "../reuse.module.css";
+
+export interface SideIndicatorItem {
+ id: string;
+ label: string; // 상단/공용 라벨
+ sideLabel?: string; // 사이드 인디게이터 전용 라벨(옵션)
+}
+
+export default function SideIndicator({
+ items,
+ activeId,
+}: {
+ items: SideIndicatorItem[];
+ activeId: string;
+}) {
+ const [manualActiveId, setManualActiveId] = useState(null);
+ const clearTimerRef = useRef(null);
+
+ const currentId = (manualActiveId ?? activeId ?? "main") || "main";
+
+ // ✅ manualActiveId가 observer(activeId)와 불일치하기 시작하면 즉시 해제 (stuck 방지)
+ useEffect(() => {
+ if (!manualActiveId) return;
+ if (activeId && activeId !== manualActiveId) setManualActiveId(null);
+ }, [activeId, manualActiveId]);
+
+ // ✅ fallback: 스무스 스크롤 시간이 길어도 manual이 오래 남지 않게 타임아웃 해제
+ useEffect(() => {
+ return () => {
+ if (clearTimerRef.current) window.clearTimeout(clearTimerRef.current);
+ };
+ }, []);
+
+ const scrollTo = (id: string) => {
+ setManualActiveId(id);
+
+ // 기존 타이머 제거 후 새로 설정
+ if (clearTimerRef.current) window.clearTimeout(clearTimerRef.current);
+ clearTimerRef.current = window.setTimeout(() => {
+ setManualActiveId(null);
+ }, 1600);
+
+ if (id === "main") {
+ window.scrollTo({ top: 0, behavior: "smooth" });
+ return;
+ }
+
+ document.getElementById(id)?.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/apps/dm_new/app/main/_hooks/useScrollSpy.ts b/apps/dm_new/app/main/_hooks/useScrollSpy.ts
new file mode 100644
index 000000000..3a253e95d
--- /dev/null
+++ b/apps/dm_new/app/main/_hooks/useScrollSpy.ts
@@ -0,0 +1,55 @@
+"use client";
+import { useEffect, useRef, useState } from "react";
+
+export function useScrollSpy(sectionIds: string[], options?: IntersectionObserverInit) {
+ const [activeId, setActiveId] = useState(sectionIds[0] ?? "");
+ const ratiosRef = useRef