fix 關閉籌備中頁面的連結
This commit is contained in:
+115
-7
@@ -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"]'));
|
||||||
|
|
||||||
soonLinks.forEach((link) => {
|
const blockNavigation = (event) => {
|
||||||
link.addEventListener("click", (event) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
});
|
};
|
||||||
|
soonLinks.forEach((link) => {
|
||||||
|
link.addEventListener("click", blockNavigation);
|
||||||
|
link.addEventListener("auxclick", blockNavigation);
|
||||||
});
|
});
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
@@ -84,10 +183,19 @@
|
|||||||
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();
|
||||||
|
if (!isSoon && !item.classList.contains("coming-soon")) {
|
||||||
item.classList.toggle("open");
|
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");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user