416 lines
14 KiB
TypeScript
416 lines
14 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
|
|
export default function GreywaterExampleSection() {
|
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const root = rootRef.current;
|
|
if (!root) return;
|
|
|
|
const cleanups: Array<() => void> = [];
|
|
const sliders = Array.from(root.querySelectorAll(".image-slider"));
|
|
|
|
sliders.forEach((sliderElement) => {
|
|
const slider = sliderElement as HTMLElement;
|
|
const viewport = slider.querySelector(
|
|
".image-slider-viewport",
|
|
) as HTMLElement | null;
|
|
const track = slider.querySelector(".image-slider-track") as HTMLElement | null;
|
|
const dotsWrap = slider.querySelector(
|
|
".image-slider-dots",
|
|
) as HTMLElement | null;
|
|
const pages = Array.from(
|
|
slider.querySelectorAll(".image-slider-page"),
|
|
) as HTMLElement[];
|
|
|
|
if (!viewport || !track || !dotsWrap || pages.length === 0) return;
|
|
|
|
let page = 0;
|
|
let dragging = false;
|
|
let isHover = false;
|
|
let startX = 0;
|
|
let deltaX = 0;
|
|
let timer: number | null = null;
|
|
|
|
const autoPlayMs = Number(slider.dataset.autoplay ?? "4500");
|
|
const canSlide = pages.length > 1;
|
|
|
|
if (!canSlide) {
|
|
dotsWrap.style.display = "none";
|
|
} else {
|
|
dotsWrap.style.display = "";
|
|
}
|
|
|
|
const render = () => {
|
|
track.style.transform = `translateX(-${page * 100}%)`;
|
|
|
|
Array.from(dotsWrap.querySelectorAll("button")).forEach((dot, index) => {
|
|
dot.classList.toggle("is-active", index === page);
|
|
});
|
|
};
|
|
|
|
const goTo = (nextPage: number) => {
|
|
if (!canSlide) return;
|
|
|
|
if (nextPage < 0) page = pages.length - 1;
|
|
else if (nextPage >= pages.length) page = 0;
|
|
else page = nextPage;
|
|
|
|
render();
|
|
};
|
|
|
|
const stopTimer = () => {
|
|
if (timer !== null) {
|
|
window.clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
};
|
|
|
|
const startTimer = () => {
|
|
stopTimer();
|
|
if (!canSlide || dragging || isHover) return;
|
|
|
|
timer = window.setInterval(() => {
|
|
page = page + 1 >= pages.length ? 0 : page + 1;
|
|
render();
|
|
}, autoPlayMs);
|
|
};
|
|
|
|
const dotButtons = pages.map((_, index) => {
|
|
const button = document.createElement("button");
|
|
button.type = "button";
|
|
button.className = "image-slider-dot";
|
|
|
|
const onClick = () => {
|
|
goTo(index);
|
|
startTimer();
|
|
};
|
|
|
|
button.addEventListener("click", onClick);
|
|
dotsWrap.appendChild(button);
|
|
|
|
cleanups.push(() => {
|
|
button.removeEventListener("click", onClick);
|
|
});
|
|
|
|
return button;
|
|
});
|
|
|
|
const onMouseEnter = () => {
|
|
isHover = true;
|
|
stopTimer();
|
|
};
|
|
|
|
const onMouseLeave = () => {
|
|
isHover = false;
|
|
startTimer();
|
|
};
|
|
|
|
const onPointerDown = (event: PointerEvent) => {
|
|
if (!canSlide) return;
|
|
|
|
dragging = true;
|
|
startX = event.clientX;
|
|
deltaX = 0;
|
|
viewport.setPointerCapture(event.pointerId);
|
|
};
|
|
|
|
const onPointerMove = (event: PointerEvent) => {
|
|
if (!dragging) return;
|
|
deltaX = event.clientX - startX;
|
|
};
|
|
|
|
const onPointerUp = () => {
|
|
if (!dragging) return;
|
|
|
|
dragging = false;
|
|
|
|
if (deltaX > 50) goTo(page - 1);
|
|
if (deltaX < -50) goTo(page + 1);
|
|
|
|
deltaX = 0;
|
|
startTimer();
|
|
};
|
|
|
|
viewport.addEventListener("mouseenter", onMouseEnter);
|
|
viewport.addEventListener("mouseleave", onMouseLeave);
|
|
viewport.addEventListener("pointerdown", onPointerDown);
|
|
viewport.addEventListener("pointermove", onPointerMove);
|
|
viewport.addEventListener("pointerup", onPointerUp);
|
|
viewport.addEventListener("pointercancel", onPointerUp);
|
|
|
|
cleanups.push(() => {
|
|
stopTimer();
|
|
viewport.removeEventListener("mouseenter", onMouseEnter);
|
|
viewport.removeEventListener("mouseleave", onMouseLeave);
|
|
viewport.removeEventListener("pointerdown", onPointerDown);
|
|
viewport.removeEventListener("pointermove", onPointerMove);
|
|
viewport.removeEventListener("pointerup", onPointerUp);
|
|
viewport.removeEventListener("pointercancel", onPointerUp);
|
|
dotButtons.forEach((button) => button.remove());
|
|
});
|
|
|
|
render();
|
|
startTimer();
|
|
});
|
|
|
|
return () => {
|
|
cleanups.forEach((cleanup) => cleanup());
|
|
};
|
|
}, []);
|
|
|
|
const contentsHtml = `
|
|
<div class="contents-page">
|
|
<div class="page-title">
|
|
<h2>
|
|
<span class="title-text">중수도 사례</span>
|
|
<span class="title-bg"> </span>
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="sections greywater-example-sections">
|
|
<section id="example-greywater-ansan" class="section first">
|
|
<div class="section-title">
|
|
<span class="section-bar"> </span>
|
|
<h3>경기도 안산시</h3>
|
|
</div>
|
|
|
|
<div class="content-group">
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업명</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>안산시 중수도 설치사업</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업목적</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>수자원을 효율적으로 활용하여 지속가능성 도모 및 물 절약 실현</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업 주요 내용</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>총사업비 : 81억원</li>
|
|
<li>처리공법 : MBLM공법</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업량</h4>
|
|
</div>
|
|
<div class="table-wrap greywater-table-wrap">
|
|
<table class="contents-table greywater-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="th-blue">시설명</th>
|
|
<th class="th-teal-greywater">이용용도</th>
|
|
<th class="th-green">공급량(㎥)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>경기테크노파크</td><td>청소·화장실용수</td><td>40㎥/일</td></tr>
|
|
<tr><td>올림픽수영장</td><td>청소·화장실/세척·살수용수</td><td>35㎥/일</td></tr>
|
|
<tr><td>와스타디움</td><td>청소·화장실/조경용수</td><td>90㎥/일</td></tr>
|
|
<tr><td>호수실내수영장</td><td>청소·화장실/조경/세척·살수용수</td><td>50㎥/일</td></tr>
|
|
<tr><td>한양대학교 에리카캠퍼스</td><td>청소·화장실용수</td><td>370㎥/일</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section id="example-greywater-yongin" class="section">
|
|
<div class="section-title">
|
|
<span class="section-bar"> </span>
|
|
<h3>경기도 용인시</h3>
|
|
</div>
|
|
|
|
|
|
<div class="content-group">
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업명</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>용인시 중수도 설치사업</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업목적</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>물 부족 등의 비상상황에 대한 대비, 하수라도 사용할 집결 등 수자원의 효율적 활용</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업 주요 내용</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>총사업비 : 40억원</li>
|
|
<li>처리공법 : MBLM공법</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업량</h4>
|
|
</div>
|
|
<div class="table-wrap greywater-table-wrap">
|
|
<table class="contents-table greywater-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="th-blue">시설명</th>
|
|
<th class="th-teal-greywater">이용용도</th>
|
|
<th class="th-green">공급량(㎥)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>여성회관</td><td>청소·화장실용수</td><td>35㎥/일</td></tr>
|
|
<tr><td>수지아르피아</td><td>청소·화장실용수</td><td>35㎥/일</td></tr>
|
|
<tr><td>지상작전사령부</td><td>청소·화장실/조경/세척·살수용수</td><td>53㎥/일</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<section id="example-greywater-pyeongtaek" class="section">
|
|
<div class="section-title">
|
|
<span class="section-bar"> </span>
|
|
<h3>경기도 평택시</h3>
|
|
</div>
|
|
|
|
|
|
<div class="content-group">
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업명</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>평택시 중수도 설치사업</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업목적</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>수자원을 효율적으로 활용하여 지속가능성 도모 및 물 절약 실현</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업 주요 내용</h4>
|
|
</div>
|
|
<ul class="bullet-list">
|
|
<li>총사업비 : 21억원</li>
|
|
<li>처리공법 : MBLM공법</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="content-block">
|
|
<div class="block-title">
|
|
<span class="block-title-icon">
|
|
<span class="bubble bubble-sky"> </span>
|
|
<span class="bubble bubble-green"> </span>
|
|
</span>
|
|
<h4>사업량</h4>
|
|
</div>
|
|
<div class="table-wrap greywater-table-wrap">
|
|
<table class="contents-table greywater-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="th-blue">시설명</th>
|
|
<th class="th-teal-greywater">이용용도</th>
|
|
<th class="th-green">공급량(㎥)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>평택대학교</td><td>청소·화장실용수</td><td>50㎥/일</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
return (
|
|
<div
|
|
ref={rootRef}
|
|
className="bg-white"
|
|
dangerouslySetInnerHTML={{ __html: contentsHtml }}
|
|
/>
|
|
);
|
|
}
|