fix 關閉籌備中頁面的連結

This commit is contained in:
2026-05-13 16:20:07 +08:00
parent 4275b0ac92
commit 627401bca7
2 changed files with 188 additions and 55 deletions
+117 -9
View File
@@ -1,4 +1,100 @@
(() => { (() => {
/**
* ── 頁面籌備中:開關方式 ─────────────────────────────────────────
* ① 整個檔案先關:COMING_SOON_PAGES 列出主檔名(目前已含長卷/電子書/志源頁/演唱會/典藏/地圖等)。
* ② index.html 細到錨點:改 INDEX_NAV_OPEN_HASHES;列在其中的 #才可點,其餘同檔連結為籌備中。
* ③ 視覺:「(頁面籌備中)」由 style.css 的 ::after 在 hover/鍵盤 focus 時才顯示,
* title 與 aria-label 供觸控長按/螢幕閱讀器補充說明。
* 要開放某連結:從對應 Set 移除檔名或補上錨點後重新整理。
*/
const COMING_SOON_PAGES = new Set([
"chronicle.html",
"ssg2-ebook.html",
"jiwon.html",
"concert.html",
"archive.html",
"map.html",
]);
/** 目前先開:淪陷瞬間 #origin + 子選單三項 #start / #mission / #timeline */
const INDEX_NAV_OPEN_HASHES = new Set(["#origin", "#start", "#mission", "#timeline"]);
function normalizePageKey(href) {
if (!href || href === "#") return "";
const core = href.split("#")[0].split("?")[0];
const parts = core.split("/").filter(Boolean);
const last = parts.length ? parts[parts.length - 1] : "";
return last.toLowerCase();
}
/** 比照原邏輯:取 href 前半與網址列檔名比對 */
function hrefMatchesCurrentPage(href, currentPage) {
if (!href || href === "#") return false;
const [filePart] = href.split("#");
const base = filePart.split("/").pop();
return base === currentPage;
}
/** 取得 #fragment(含 #);若無錨點則回傳空字串 */
function anchorFromHref(href) {
const i = href.indexOf("#");
if (i < 0) return "";
return href.slice(i).split("?")[0];
}
function markLinkComingSoon(link, originalHref) {
const visibleTitle = link.textContent.trim();
link.setAttribute("data-coming-soon", "true");
link.setAttribute("aria-disabled", "true");
link.setAttribute("title", "頁面籌備中");
link.setAttribute("aria-label", `${visibleTitle}(頁面籌備中)`);
if (!link.dataset.originalHref) {
link.dataset.originalHref = originalHref;
}
link.setAttribute("href", "#");
}
function linkShouldBeComingSoon(href, pageKey, pageKeysSoon) {
if (pageKeysSoon.has(pageKey)) {
return true;
}
if (pageKey === "index.html") {
const frag = anchorFromHref(href);
return !INDEX_NAV_OPEN_HASHES.has(frag);
}
return false;
}
/** 將籌備中規則套用至單一導覽列 */
function applyComingSoonToNav(nav) {
const pageKeysSoon = new Set(
[...COMING_SOON_PAGES].map((p) => normalizePageKey(String(p))).filter(Boolean),
);
nav.querySelectorAll('a[href]').forEach((link) => {
if (link.classList.contains("logo")) return;
const href = link.getAttribute("href");
if (!href || href === "#") return;
const pageKey = normalizePageKey(href);
if (!pageKey) return;
if (!linkShouldBeComingSoon(href, pageKey, pageKeysSoon)) return;
markLinkComingSoon(link, href);
});
nav.querySelectorAll(":scope > ul > li").forEach((li) => {
const trigger = li.querySelector(":scope > a[href]");
if (!trigger || trigger.classList.contains("logo")) return;
if (trigger.getAttribute("data-coming-soon") === "true") {
li.classList.add("coming-soon");
}
});
}
/** 全站導覽 HTML — 僅修改此字串即可同步所有頁面 */ /** 全站導覽 HTML — 僅修改此字串即可同步所有頁面 */
const PORTAL_NAV_INNER_HTML = ` const PORTAL_NAV_INNER_HTML = `
<a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a> <a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a>
@@ -42,6 +138,7 @@
document.querySelectorAll("nav.portal-nav[data-portal-nav]").forEach((nav) => { document.querySelectorAll("nav.portal-nav[data-portal-nav]").forEach((nav) => {
nav.innerHTML = PORTAL_NAV_INNER_HTML; nav.innerHTML = PORTAL_NAV_INNER_HTML;
applyComingSoonToNav(nav);
}); });
const navs = Array.from(document.querySelectorAll(".portal-nav")); const navs = Array.from(document.querySelectorAll(".portal-nav"));
@@ -53,11 +150,13 @@
const items = Array.from(nav.querySelectorAll("li")); const items = Array.from(nav.querySelectorAll("li"));
const soonLinks = Array.from(nav.querySelectorAll('a[data-coming-soon="true"]')); const soonLinks = Array.from(nav.querySelectorAll('a[data-coming-soon="true"]'));
const blockNavigation = (event) => {
event.preventDefault();
event.stopPropagation();
};
soonLinks.forEach((link) => { soonLinks.forEach((link) => {
link.addEventListener("click", (event) => { link.addEventListener("click", blockNavigation);
event.preventDefault(); link.addEventListener("auxclick", blockNavigation);
event.stopPropagation();
});
}); });
items.forEach((item) => { items.forEach((item) => {
@@ -84,9 +183,18 @@
trigger.addEventListener("focus", openItem); trigger.addEventListener("focus", openItem);
trigger.addEventListener("click", (event) => { trigger.addEventListener("click", (event) => {
const isSoon = trigger.getAttribute("data-coming-soon") === "true";
if (window.innerWidth <= 1024) { if (window.innerWidth <= 1024) {
event.preventDefault(); event.preventDefault();
item.classList.toggle("open"); if (!isSoon && !item.classList.contains("coming-soon")) {
item.classList.toggle("open");
}
return;
}
if (isSoon) {
event.preventDefault();
} }
}); });
}); });
@@ -99,10 +207,10 @@
const topLevelLinks = Array.from(nav.querySelectorAll(":scope > ul > li > a[href]")); const topLevelLinks = Array.from(nav.querySelectorAll(":scope > ul > li > a[href]"));
topLevelLinks.forEach((link) => { topLevelLinks.forEach((link) => {
const href = link.getAttribute("href"); const fallback = link.getAttribute("href");
if (!href) return; const source = link.dataset.originalHref || fallback;
const [file] = href.split("#"); if (!source || source === "#") return;
if (file === currentPage) { if (hrefMatchesCurrentPage(source, currentPage)) {
link.classList.add("nav-current"); link.classList.add("nav-current");
} }
}); });
+71 -46
View File
@@ -150,63 +150,77 @@ nav a:hover {
} }
.portal-nav>ul>li.coming-soon>a { .portal-nav>ul>li.coming-soon>a {
position: relative;
padding-bottom: 20px;
color: #c8a66a !important;
cursor: not-allowed; cursor: not-allowed;
} opacity: 0.82;
color: rgba(212, 196, 150, 0.95);
.portal-nav>ul>li.coming-soon>a::after {
content: "建置中";
position: absolute;
left: 50%;
bottom: -8px;
transform: translateX(-50%);
white-space: nowrap;
line-height: 1;
font-size: 0.72rem;
letter-spacing: 0.5px;
color: #fff;
background: #a66a2d;
border-radius: 999px;
padding: 4px 10px;
} }
.portal-nav a[data-coming-soon="true"] { .portal-nav a[data-coming-soon="true"] {
cursor: not-allowed; cursor: not-allowed;
opacity: 0.72; opacity: 0.82;
position: relative;
}
.portal-nav a[data-coming-soon="true"]::after {
content: "(頁面籌備中)";
position: absolute;
z-index: 120;
white-space: nowrap;
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.02em;
color: #6a4818;
background: #fff9e6;
padding: 5px 11px;
border-radius: 8px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
opacity: 0;
pointer-events: none;
transition: opacity 0.16s ease;
}
.portal-nav>ul>li>a[data-coming-soon="true"]::after {
left: 50%;
top: calc(100% + 4px);
transform: translateX(-50%);
}
.portal-nav .portal-submenu a[data-coming-soon="true"]::after {
left: 50%;
top: calc(100% + 2px);
transform: translateX(-50%);
}
.portal-nav>ul>li>a[data-coming-soon="true"]:hover,
.portal-nav>ul>li>a[data-coming-soon="true"]:focus-visible {
color: rgba(212, 196, 150, 0.95);
}
.portal-nav .portal-submenu a[data-coming-soon="true"]:hover,
.portal-nav .portal-submenu a[data-coming-soon="true"]:focus-visible {
background-color: transparent;
color: #5f5f5f;
}
@media (hover: hover) {
.portal-nav a[data-coming-soon="true"]:hover::after,
.portal-nav a[data-coming-soon="true"]:focus-visible::after {
opacity: 1;
}
}
@media (hover: none) {
.portal-nav a[data-coming-soon="true"]:active::after {
opacity: 1;
transition: opacity 0.08s ease;
}
} }
.portal-nav li.coming-soon>.portal-submenu { .portal-nav li.coming-soon>.portal-submenu {
display: none !important; display: none !important;
} }
.portal-nav .portal-submenu a[data-coming-soon="true"] {
position: relative;
}
.portal-nav .portal-submenu a[data-coming-soon="true"]::after {
content: "建置中";
position: absolute;
top: 50%;
right: -78px;
transform: translateY(-50%);
font-size: 0.72rem;
letter-spacing: 0.5px;
color: #fff;
background: #a66a2d;
border-radius: 999px;
padding: 4px 10px;
opacity: 0;
pointer-events: none;
transition: opacity 0.18s ease;
}
.portal-nav .portal-submenu a[data-coming-soon="true"]:hover::after,
.portal-nav .portal-submenu a[data-coming-soon="true"]:focus-visible::after {
opacity: 1;
}
.portal-nav li:hover>.portal-submenu, .portal-nav li:hover>.portal-submenu,
.portal-nav li:focus-within>.portal-submenu, .portal-nav li:focus-within>.portal-submenu,
.portal-nav li.open>.portal-submenu { .portal-nav li.open>.portal-submenu {
@@ -938,6 +952,17 @@ footer {
color: #3a300a; color: #3a300a;
} }
.map-page .portal-nav>ul>li>a[data-coming-soon="true"]:hover,
.map-page .portal-nav>ul>li>a[data-coming-soon="true"]:focus-visible {
color: rgba(212, 196, 150, 0.95);
}
.map-page .portal-nav .portal-submenu a[data-coming-soon="true"]:hover,
.map-page .portal-nav .portal-submenu a[data-coming-soon="true"]:focus-visible {
background-color: transparent;
color: #5f5f5f;
}
.map-archive-header { .map-archive-header {
width: 100%; width: 100%;
height: 100vh; height: 100vh;