Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions assets/js/scroll-reveal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 스크롤 리빌 — .skt-reveal 요소가 뷰포트에 들어오면 .is-visible 을 부여해
* 부드럽게 나타나게 한다. 의존성 없는 순수 JS(IntersectionObserver).
*
* 초기 숨김(opacity:0)은 CSS에서 html.js-reveal 일 때만 적용되며, 이 클래스는
* 동작 줄이기(prefers-reduced-motion)가 아닐 때만 head 인라인 스크립트가 부여한다.
* 따라서 JS 비활성/실패 또는 동작 줄이기 환경에서는 콘텐츠가 항상 보인다.
*/
(function () {
"use strict";

var root = document.documentElement;

// js-reveal 게이트가 없으면(동작 줄이기 등) 아무것도 숨기지 않은 상태이므로 종료
if (!root.classList.contains("js-reveal")) return;

var els = document.querySelectorAll(".skt-reveal");

// 관찰 대상이 없거나 IO 미지원 → 게이트를 풀어 전부 보이게 하고 종료
if (!els.length || !("IntersectionObserver" in window)) {
root.classList.remove("js-reveal");
return;
}

var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
io.unobserve(entry.target);
}
});
}, { rootMargin: "0px 0px -8% 0px", threshold: 0.08 });

els.forEach(function (el) { io.observe(el); });
})();
55 changes: 55 additions & 0 deletions assets/js/ui-enhancements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* UI 보조 요소 — 스크롤 진행 바 + 맨 위로 버튼. 의존성 없는 순수 JS.
* 동작 줄이기(prefers-reduced-motion)일 때 부드러운 스크롤 대신 즉시 이동한다.
*/
(function () {
"use strict";

var reduce = window.matchMedia &&
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
var isEn = (document.documentElement.lang || "").slice(0, 2) === "en";

// 0) 스킵 링크 — 키보드 사용자가 반복되는 내비를 건너뛰고 본문으로 (접근성)
var main = document.querySelector("main");
if (main) {
if (!main.id) main.id = "main-content";
var skip = document.createElement("a");
skip.className = "skt-skip-link";
skip.href = "#" + main.id;
skip.textContent = isEn ? "Skip to content" : "본문 바로가기";
document.body.insertBefore(skip, document.body.firstChild);
}

// 1) 스크롤 진행 바 (상단 고정, 액센트색)
var bar = document.createElement("div");
bar.className = "skt-progress";
bar.setAttribute("aria-hidden", "true");
document.body.appendChild(bar);

// 2) 맨 위로 버튼
var btn = document.createElement("button");
btn.type = "button";
btn.className = "skt-to-top";
btn.setAttribute("aria-label", isEn ? "Back to top" : "맨 위로");
btn.innerHTML = '<i class="fas fa-arrow-up" aria-hidden="true"></i>';
btn.addEventListener("click", function () {
window.scrollTo({ top: 0, behavior: reduce ? "auto" : "smooth" });
});
document.body.appendChild(btn);

var ticking = false;
function update() {
var doc = document.documentElement;
var st = window.scrollY || doc.scrollTop;
var h = doc.scrollHeight - doc.clientHeight;
bar.style.transform = "scaleX(" + (h > 0 ? st / h : 0) + ")";
btn.classList.toggle("is-visible", st > 400);
ticking = false;
}
function onScroll() {
if (!ticking) { window.requestAnimationFrame(update); ticking = true; }
}
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll, { passive: true });
update();
})();
Loading
Loading