feat 整合多頁面 導覽列
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-TW">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>水晶男孩|十六年約定</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="chronicle-page">
|
||||||
|
<header class="map-archive-header">
|
||||||
|
<div class="header-inner">
|
||||||
|
<h1 class="main-title">十六年約定</h1>
|
||||||
|
<div class="subtitle-wrap">
|
||||||
|
<span class="sub-title">SECHSKIES COM' BACK · APRIL 14 · 2016</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽">
|
||||||
|
<a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="index.html#intro">淪陷瞬間</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="index.html#mission">成立的初衷</a></li>
|
||||||
|
<li><a href="index.html#current">跨時空軌跡</a></li>
|
||||||
|
<li><a href="index.html#story">好奇的代價</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="chronicle.html">十六年約定</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="#challenge">無限挑戰</a></li>
|
||||||
|
<li><a href="#ssg2">六六歌第二季</a></li>
|
||||||
|
<li><a href="#sechskies-profile">水晶男孩</a></li>
|
||||||
|
<li><a href="#gather">召集</a></li>
|
||||||
|
<li><a href="#negotiate">正式交涉</a></li>
|
||||||
|
<li><a href="#variables">變數</a></li>
|
||||||
|
<li><a href="#surprise">驚喜</a></li>
|
||||||
|
<li><a href="#final-stage">登場</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="index.html#archive">黃色留聲機</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="classic.html">輝煌全盛期</a></li>
|
||||||
|
<li><a href="index.html#new">啟動新篇章</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="concert.html">現場的悸動</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="concert.html#classic-stage" data-coming-soon="true" aria-disabled="true">燦爛的最初</a></li>
|
||||||
|
<li><a href="concert.html#reunion-stage">永恆的重逢</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="coming-soon"><a href="variety.html" data-coming-soon="true" aria-disabled="true">綜藝熱播中</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="variety.html#jiwon" data-coming-soon="true" aria-disabled="true">瘋子與天才</a></li>
|
||||||
|
<li><a href="variety.html#group" data-coming-soon="true" aria-disabled="true">舞台外真實</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="map.html">聖地巡禮</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="map.html#taiwan">台灣聖地</a></li>
|
||||||
|
<li><a href="map.html#global">海外遠征</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<canvas id="particles"></canvas>
|
||||||
|
|
||||||
|
<div class="chronicle-controls content-container">
|
||||||
|
<button class="mode-btn active" data-mode="scroll">網漫模式(一路滑下去)</button>
|
||||||
|
<button class="mode-btn" data-mode="paged">分頁模式(上一頁 / 下一頁)</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main class="content-container chronicle-reader" id="chronicle-reader" data-mode="scroll">
|
||||||
|
<article class="chronicle-chapter active" id="challenge" data-title="無限挑戰">
|
||||||
|
<h2>04 無限挑戰</h2>
|
||||||
|
<p>《無限挑戰》是韓國綜藝史上指標性的真人秀節目。「星期六星期六是歌手(六六歌)」企劃,成為水晶男孩 2016 回歸舞台的關鍵起點。</p>
|
||||||
|
<p>第一季掀起 90 年代懷舊熱潮,雖然水晶男孩未能完整出演,卻留下「總有一天要六人完整回到舞台」的遺憾伏筆。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="ssg2" data-title="六六歌第二季">
|
||||||
|
<h2>06 六六歌第二季</h2>
|
||||||
|
<p>第二季改成「為單一團體打造完整回歸敘事」,保密層級更高,連主持群都縮小到劉在錫與 HAHA,避免消息提前走漏。</p>
|
||||||
|
<p>從開場的復古裝扮、試探式線索到真正揭曉團體身份,節目節奏在搞笑與懸念間拉開這場 16 年重逢序章。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="sechskies-profile" data-title="水晶男孩">
|
||||||
|
<h2>08 水晶男孩</h2>
|
||||||
|
<p>1997 出道後迅速登頂,與同世代頂流並列,短短三年創下極高銷量與舞台紀錄,卻在 2000 無預警解散,留下集體創傷。</p>
|
||||||
|
<p>16 年間六人從未以水晶男孩名義完整合體,這次企劃不只是回憶,而是回應當年未說完的離別。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="gather" data-title="召集">
|
||||||
|
<h2>10 召集</h2>
|
||||||
|
<p>製作組先與隊長殷志源交涉,再透過隱藏攝影機確認成員意願。大家都希望重組,卻同時知道最困難的拼圖是離開演藝圈多年的高志溶。</p>
|
||||||
|
<p>這個階段的重點不是舞台,而是「願不願意再次站在一起」的心理門檻。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="negotiate" data-title="正式交涉">
|
||||||
|
<h2>11 正式交涉</h2>
|
||||||
|
<p>主持人與成員深度對話,回顧解散緣由、舞台記憶、KTV 挑戰與游擊演唱會規則。笑鬧之間,團魂逐漸浮現。</p>
|
||||||
|
<p>同時,節目也把高志溶議題正式擺上檯面:如果不是完整體,這次回歸是否還成立?</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="variables" data-title="變數">
|
||||||
|
<h2>16 變數</h2>
|
||||||
|
<p>排練期間接連出現傷病、手術需求與消息外流,原本理想的游擊演唱會計畫屢次被迫改寫,團隊陷入 B 計畫陰影。</p>
|
||||||
|
<p>在體力與心理都被拉到極限的情況下,成員仍選擇撐住,只為把久違舞台交回給等待 16 年的小黃。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="surprise" data-title="驚喜">
|
||||||
|
<h2>19 驚喜</h2>
|
||||||
|
<p>當所有人幾乎接受「不完整」時,節目仍悄悄推進最後安排。高志溶與成員的情感張力在此段達到最高點。</p>
|
||||||
|
<p>這份驚喜不是綜藝反轉,而是把六顆水晶的空位真正填回舞台。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="chronicle-chapter" id="final-stage" data-title="登場">
|
||||||
|
<h2>21 登場</h2>
|
||||||
|
<p>眼罩揭開後,滿場黃海與哭聲同時湧現。從《請記得我》到安可,《離別曲》在那一晚變成了「重逢證詞」。</p>
|
||||||
|
<p>2000 的缺憾,在 2016 終於補上。這一頁不是結束,而是團體與粉絲共同完成的回歸章節。</p>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div class="chronicle-pager content-container" id="chronicle-pager" hidden>
|
||||||
|
<button id="prev-chapter" class="btn">上一頁</button>
|
||||||
|
<span id="chapter-indicator">1 / 8</span>
|
||||||
|
<button id="next-chapter" class="btn">下一頁</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||||
|
<a href="https://jekkinoopy.github.io/Portfolio/" class="studio-link" target="_blank">
|
||||||
|
Design by <strong>Jekkinoopy Studio</strong>
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="portal-nav.js"></script>
|
||||||
|
<script src="particles.js"></script>
|
||||||
|
<script src="chronicle.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
(() => {
|
||||||
|
const reader = document.getElementById("chronicle-reader");
|
||||||
|
if (!reader) return;
|
||||||
|
|
||||||
|
const chapters = Array.from(reader.querySelectorAll(".chronicle-chapter"));
|
||||||
|
const modeButtons = Array.from(document.querySelectorAll(".mode-btn"));
|
||||||
|
const pager = document.getElementById("chronicle-pager");
|
||||||
|
const prevBtn = document.getElementById("prev-chapter");
|
||||||
|
const nextBtn = document.getElementById("next-chapter");
|
||||||
|
const indicator = document.getElementById("chapter-indicator");
|
||||||
|
let currentIndex = 0;
|
||||||
|
|
||||||
|
function updatePagedView() {
|
||||||
|
chapters.forEach((chapter, index) => {
|
||||||
|
chapter.style.display = index === currentIndex ? "" : "none";
|
||||||
|
chapter.classList.toggle("active", index === currentIndex);
|
||||||
|
});
|
||||||
|
indicator.textContent = `${currentIndex + 1} / ${chapters.length}`;
|
||||||
|
prevBtn.disabled = currentIndex === 0;
|
||||||
|
nextBtn.disabled = currentIndex === chapters.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMode(mode) {
|
||||||
|
reader.dataset.mode = mode;
|
||||||
|
modeButtons.forEach((btn) => btn.classList.toggle("active", btn.dataset.mode === mode));
|
||||||
|
if (mode === "paged") {
|
||||||
|
pager.hidden = false;
|
||||||
|
updatePagedView();
|
||||||
|
} else {
|
||||||
|
pager.hidden = true;
|
||||||
|
chapters.forEach((chapter) => {
|
||||||
|
chapter.style.display = "";
|
||||||
|
chapter.classList.remove("active");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modeButtons.forEach((button) => {
|
||||||
|
button.addEventListener("click", () => setMode(button.dataset.mode));
|
||||||
|
});
|
||||||
|
|
||||||
|
prevBtn.addEventListener("click", () => {
|
||||||
|
if (currentIndex > 0) {
|
||||||
|
currentIndex -= 1;
|
||||||
|
updatePagedView();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nextBtn.addEventListener("click", () => {
|
||||||
|
if (currentIndex < chapters.length - 1) {
|
||||||
|
currentIndex += 1;
|
||||||
|
updatePagedView();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setMode("scroll");
|
||||||
|
})();
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-TW">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>水晶男孩|輝煌全盛期</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="hero">
|
||||||
|
<h1>輝煌全盛期</h1>
|
||||||
|
<p>26 年前的經典作品整理</p>
|
||||||
|
<a href="#classic-albums" class="btn">查看專輯清單</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽">
|
||||||
|
<a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="index.html#intro">淪陷瞬間</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="index.html#mission">成立的初衷</a></li>
|
||||||
|
<li><a href="index.html#current">跨時空軌跡</a></li>
|
||||||
|
<li><a href="index.html#story">好奇的代價</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="chronicle.html">十六年約定</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="chronicle.html#challenge">無限挑戰</a></li>
|
||||||
|
<li><a href="chronicle.html#ssg2">六六歌第二季</a></li>
|
||||||
|
<li><a href="chronicle.html#sechskies-profile">水晶男孩</a></li>
|
||||||
|
<li><a href="chronicle.html#gather">召集</a></li>
|
||||||
|
<li><a href="chronicle.html#negotiate">正式交涉</a></li>
|
||||||
|
<li><a href="chronicle.html#variables">變數</a></li>
|
||||||
|
<li><a href="chronicle.html#surprise">驚喜</a></li>
|
||||||
|
<li><a href="chronicle.html#final-stage">登場</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="index.html#archive">黃色留聲機</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="classic.html">輝煌全盛期</a></li>
|
||||||
|
<li><a href="index.html#new">啟動新篇章</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="concert.html">現場的悸動</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="concert.html#classic-stage" data-coming-soon="true" aria-disabled="true">燦爛的最初</a></li>
|
||||||
|
<li><a href="concert.html#reunion-stage">永恆的重逢</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="coming-soon"><a href="variety.html" data-coming-soon="true" aria-disabled="true">綜藝熱播中</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="variety.html#jiwon" data-coming-soon="true" aria-disabled="true">瘋子與天才</a></li>
|
||||||
|
<li><a href="variety.html#group" data-coming-soon="true" aria-disabled="true">舞台外真實</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="map.html">聖地巡禮</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="map.html#taiwan">台灣聖地</a></li>
|
||||||
|
<li><a href="map.html#global">海外遠征</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<canvas id="particles"></canvas>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<section id="classic-albums">
|
||||||
|
<h2 class="section-title">輝煌全盛期 (精選)</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>年份</th>
|
||||||
|
<th>專輯/作品</th>
|
||||||
|
<th>主打歌</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>1997</td>
|
||||||
|
<td>學園別曲</td>
|
||||||
|
<td>學園別曲 / 男兒之路 (Pom Saeng Pom Sa)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>1998</td>
|
||||||
|
<td>Road Fighter</td>
|
||||||
|
<td>Road Fighter / Couple</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>1999</td>
|
||||||
|
<td>Com'Back</td>
|
||||||
|
<td>Com'Back</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('particles');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
let particles = [];
|
||||||
|
class Particle {
|
||||||
|
constructor() {
|
||||||
|
this.x = Math.random() * canvas.width;
|
||||||
|
this.y = Math.random() * canvas.height;
|
||||||
|
this.size = Math.random() * 4 + 1;
|
||||||
|
this.speedX = Math.random() * 0.5 - 0.25;
|
||||||
|
this.speedY = Math.random() * 0.5 + 0.2;
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY;
|
||||||
|
if (this.y > canvas.height) this.y = 0;
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
ctx.fillStyle = '#FFDD00';
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
particles = [];
|
||||||
|
for (let i = 0; i < 80; i++) particles.push(new Particle());
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (const p of particles) {
|
||||||
|
p.update();
|
||||||
|
p.draw();
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
resizeCanvas();
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
</script>
|
||||||
|
<script src="portal-nav.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+27
-8
@@ -2,20 +2,38 @@ body {
|
|||||||
background-color: var(--);
|
background-color: var(--);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.concert-page {
|
||||||
|
background-color: var(--deep-black);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.concert-archive-header {
|
.concert-archive-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
min-height: 100dvh;
|
||||||
|
background-image: url('img/header.jpg');
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 108%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 100px 20px 80px;
|
padding: 0 20px;
|
||||||
background: #fcfaf2;
|
overflow: hidden;
|
||||||
/* 延用你的米白背景 */
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
font-size: 3.5rem;
|
font-size: 3.5rem;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
color: #333;
|
color: var(--yellow);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
letter-spacing: 10px;
|
letter-spacing: 8px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
text-shadow: 0 0 30px rgba(255, 221, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle-wrap {
|
.subtitle-wrap {
|
||||||
@@ -36,8 +54,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sub-title {
|
.sub-title {
|
||||||
font-size: 1.2rem;
|
font-size: 1rem;
|
||||||
color: #888;
|
color: #d4d4d4;
|
||||||
letter-spacing: 6px;
|
letter-spacing: 6px;
|
||||||
margin: 0 25px;
|
margin: 0 25px;
|
||||||
}
|
}
|
||||||
@@ -126,8 +144,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.concert-container {
|
.concert-container {
|
||||||
max-width: 800px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 第一層:演唱會卡片外殼 */
|
/* 第一層:演唱會卡片外殼 */
|
||||||
|
|||||||
+118
-4
@@ -1,13 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-TW">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>SECHSKIES Concert Archive</title>
|
<title>SECHSKIES Concert Archive</title>
|
||||||
<link rel="stylesheet" href="concert.css">
|
<link rel="stylesheet" href="concert.css">
|
||||||
<!-- <link rel="stylesheet" href="style.css"> -->
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body class="concert-page">
|
||||||
<!-- HTML 結構 -->
|
<!-- HTML 結構 -->
|
||||||
<header class="concert-archive-header">
|
<header class="concert-archive-header">
|
||||||
<div class="header-inner">
|
<div class="header-inner">
|
||||||
@@ -17,13 +20,62 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽">
|
||||||
|
<a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="index.html#intro">淪陷瞬間</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="index.html#mission">成立的初衷</a></li>
|
||||||
|
<li><a href="index.html#current">跨時空軌跡</a></li>
|
||||||
|
<li><a href="index.html#story">好奇的代價</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="chronicle.html">十六年約定</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="chronicle.html#challenge">無限挑戰</a></li>
|
||||||
|
<li><a href="chronicle.html#ssg2">六六歌第二季</a></li>
|
||||||
|
<li><a href="chronicle.html#sechskies-profile">水晶男孩</a></li>
|
||||||
|
<li><a href="chronicle.html#gather">召集</a></li>
|
||||||
|
<li><a href="chronicle.html#negotiate">正式交涉</a></li>
|
||||||
|
<li><a href="chronicle.html#variables">變數</a></li>
|
||||||
|
<li><a href="chronicle.html#surprise">驚喜</a></li>
|
||||||
|
<li><a href="chronicle.html#final-stage">登場</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="index.html#archive">黃色留聲機</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="classic.html">輝煌全盛期</a></li>
|
||||||
|
<li><a href="index.html#new">啟動新篇章</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="concert.html">現場的悸動</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="concert.html#classic-stage" data-coming-soon="true" aria-disabled="true">燦爛的最初</a></li>
|
||||||
|
<li><a href="concert.html#reunion-stage">永恆的重逢</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="coming-soon"><a href="variety.html" data-coming-soon="true" aria-disabled="true">綜藝熱播中</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="variety.html#jiwon" data-coming-soon="true" aria-disabled="true">瘋子與天才</a></li>
|
||||||
|
<li><a href="variety.html#group" data-coming-soon="true" aria-disabled="true">舞台外真實</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="map.html">聖地巡禮</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="map.html#taiwan">台灣聖地</a></li>
|
||||||
|
<li><a href="map.html#global">海外遠征</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<canvas id="particles"></canvas>
|
||||||
<div class="search-section">
|
<div class="search-section">
|
||||||
<input type="text" class="search-input" placeholder="搜尋曲目或場次...">
|
<input type="text" class="search-input" placeholder="搜尋曲目或場次...">
|
||||||
</div>
|
</div>
|
||||||
<div class="concert-container">
|
<div class="concert-container">
|
||||||
|
|
||||||
<!-- 演唱會 con-$ -->
|
<!-- 演唱會 con-$ -->
|
||||||
<div class="con-1" data-tour="YELLOW NOTE">
|
<div id="classic-stage" class="con-1" data-tour="YELLOW NOTE">
|
||||||
<span class="title">2016 | YELLOW NOTE</span>
|
<span class="title">2016 | YELLOW NOTE</span>
|
||||||
<img src="img/concert/2016.jpg" alt="">
|
<img src="img/concert/2016.jpg" alt="">
|
||||||
<!-- 地點 con-$-$ -->
|
<!-- 地點 con-$-$ -->
|
||||||
@@ -151,7 +203,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 演唱會 02 -->
|
<!-- 演唱會 02 -->
|
||||||
<div class="con-2" data-tour="20TH ANNIV.">
|
<div id="reunion-stage" class="con-2" data-tour="20TH ANNIV.">
|
||||||
<span class="title">2017-2018 | 20TH ANNIVERSARY</span>
|
<span class="title">2017-2018 | 20TH ANNIVERSARY</span>
|
||||||
<img src="img/concert/2017.jpg" alt="">
|
<img src="img/concert/2017.jpg" alt="">
|
||||||
|
|
||||||
@@ -399,7 +451,69 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<footer>
|
||||||
|
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||||
|
<a href="https://jekkinoopy.github.io/Portfolio/" class="studio-link" target="_blank">
|
||||||
|
Design by <strong>Jekkinoopy Studio</strong>
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('particles');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
let particles = [];
|
||||||
|
class Particle {
|
||||||
|
constructor() {
|
||||||
|
this.x = Math.random() * canvas.width;
|
||||||
|
this.y = Math.random() * canvas.height;
|
||||||
|
this.size = Math.random() * 4 + 1;
|
||||||
|
this.speedX = Math.random() * 0.5 - 0.25;
|
||||||
|
this.speedY = Math.random() * 0.5 + 0.2;
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY;
|
||||||
|
if (this.y > canvas.height) this.y = 0;
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
ctx.fillStyle = '#FFDD00';
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
particles = [];
|
||||||
|
for (let i = 0; i < 80; i++) particles.push(new Particle());
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (const p of particles) {
|
||||||
|
p.update();
|
||||||
|
p.draw();
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
resizeCanvas();
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
</script>
|
||||||
|
<script src="portal-nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
+54
-6
@@ -20,19 +20,65 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav>
|
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽">
|
||||||
<div class="logo"><img src="./img/logov.svg" alt=""></div>
|
<a class="logo" href="index.html"><img src="./img/logov.svg" alt=""></a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#background">重拾黃色奇蹟</a></li>
|
<li><a href="index.html#intro">淪陷瞬間</a>
|
||||||
<li><a href="#albums">歷年作品</a></li>
|
<ul class="portal-submenu">
|
||||||
<li><a href="#current">現在故事線</a></li>
|
<li><a href="index.html#mission">成立的初衷</a></li>
|
||||||
<li><a href="concert.html">演唱會紀錄</a></li>
|
<li><a href="index.html#current">跨時空軌跡</a></li>
|
||||||
|
<li><a href="index.html#story">好奇的代價</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="chronicle.html">十六年約定</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="chronicle.html#challenge">無限挑戰</a></li>
|
||||||
|
<li><a href="chronicle.html#ssg2">六六歌第二季</a></li>
|
||||||
|
<li><a href="chronicle.html#sechskies-profile">水晶男孩</a></li>
|
||||||
|
<li><a href="chronicle.html#gather">召集</a></li>
|
||||||
|
<li><a href="chronicle.html#negotiate">正式交涉</a></li>
|
||||||
|
<li><a href="chronicle.html#variables">變數</a></li>
|
||||||
|
<li><a href="chronicle.html#surprise">驚喜</a></li>
|
||||||
|
<li><a href="chronicle.html#final-stage">登場</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="index.html#archive">黃色留聲機</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="classic.html">輝煌全盛期</a></li>
|
||||||
|
<li><a href="index.html#new">啟動新篇章</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="concert.html">現場的悸動</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="concert.html#classic-stage" data-coming-soon="true" aria-disabled="true">燦爛的最初</a></li>
|
||||||
|
<li><a href="concert.html#reunion-stage">永恆的重逢</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="coming-soon"><a href="variety.html" data-coming-soon="true" aria-disabled="true">綜藝熱播中</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="variety.html#jiwon" data-coming-soon="true" aria-disabled="true">瘋子與天才</a></li>
|
||||||
|
<li><a href="variety.html#group" data-coming-soon="true" aria-disabled="true">舞台外真實</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="map.html">聖地巡禮</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="map.html#taiwan">台灣聖地</a></li>
|
||||||
|
<li><a href="map.html#global">海外遠征</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<canvas id="particles"></canvas>
|
<canvas id="particles"></canvas>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div id="intro"></div>
|
||||||
|
<div id="mission"></div>
|
||||||
|
<div id="timeline"></div>
|
||||||
|
<div id="story"></div>
|
||||||
|
<div id="archive"></div>
|
||||||
|
<div id="classic"></div>
|
||||||
|
<div id="new"></div>
|
||||||
<section id="background">
|
<section id="background">
|
||||||
<h2 class="section-title">故事背景</h2>
|
<h2 class="section-title">故事背景</h2>
|
||||||
<div class="intro-text">
|
<div class="intro-text">
|
||||||
@@ -135,6 +181,7 @@
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||||
@@ -201,6 +248,7 @@
|
|||||||
init();
|
init();
|
||||||
animate();
|
animate();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="portal-nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body class="map-page">
|
||||||
<!-- 備註:本頁一定要是完整 HTML 文件(含 head 與 style.css),
|
<!-- 備註:本頁一定要是完整 HTML 文件(含 head 與 style.css),
|
||||||
否則會變成瀏覽器的「片段模式」,樣式常常吃不到或跑版。 -->
|
否則會變成瀏覽器的「片段模式」,樣式常常吃不到或跑版。 -->
|
||||||
<header class="map-archive-header">
|
<header class="map-archive-header">
|
||||||
@@ -21,24 +21,76 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav class="member-tabs" aria-label="成員篩選">
|
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽">
|
||||||
<button class="tab-btn active" data-member="all" aria-pressed="true">全部行程</button>
|
<a class="logo" href="index.html"><img src="./img/logov.svg" alt="SECHSKIES Logo"></a>
|
||||||
<button class="tab-btn" data-member="kogo" aria-pressed="false">高高父子遊台灣</button>
|
<ul>
|
||||||
|
<li><a href="index.html#intro">淪陷瞬間</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="index.html#mission">成立的初衷</a></li>
|
||||||
|
<li><a href="index.html#current">跨時空軌跡</a></li>
|
||||||
|
<li><a href="index.html#story">好奇的代價</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="chronicle.html">十六年約定</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="chronicle.html#challenge">無限挑戰</a></li>
|
||||||
|
<li><a href="chronicle.html#ssg2">六六歌第二季</a></li>
|
||||||
|
<li><a href="chronicle.html#sechskies-profile">水晶男孩</a></li>
|
||||||
|
<li><a href="chronicle.html#gather">召集</a></li>
|
||||||
|
<li><a href="chronicle.html#negotiate">正式交涉</a></li>
|
||||||
|
<li><a href="chronicle.html#variables">變數</a></li>
|
||||||
|
<li><a href="chronicle.html#surprise">驚喜</a></li>
|
||||||
|
<li><a href="chronicle.html#final-stage">登場</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="index.html#archive">黃色留聲機</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="classic.html">輝煌全盛期</a></li>
|
||||||
|
<li><a href="index.html#new">啟動新篇章</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="concert.html">現場的悸動</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="concert.html#classic-stage" data-coming-soon="true" aria-disabled="true">燦爛的最初</a></li>
|
||||||
|
<li><a href="concert.html#reunion-stage">永恆的重逢</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="coming-soon"><a href="variety.html" data-coming-soon="true" aria-disabled="true">綜藝熱播中</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="variety.html#jiwon" data-coming-soon="true" aria-disabled="true">瘋子與天才</a></li>
|
||||||
|
<li><a href="variety.html#group" data-coming-soon="true" aria-disabled="true">舞台外真實</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="map.html">聖地巡禮</a>
|
||||||
|
<ul class="portal-submenu">
|
||||||
|
<li><a href="map.html#taiwan">台灣聖地</a></li>
|
||||||
|
<li><a href="map.html#global">海外遠征</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<div class="member-tabs" aria-label="成員篩選">
|
||||||
|
<button class="tab-btn active" data-member="all" aria-pressed="true">全部行程</button>
|
||||||
|
<button class="tab-btn" data-member="ko" aria-pressed="false">高高父子遊台灣</button>
|
||||||
|
<button class="tab-btn" data-member="eun" aria-pressed="false">殷空少搭飛機去台灣高雄</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas id="particles"></canvas>
|
||||||
|
|
||||||
<input id="itinerary-search" type="search" aria-label="行程搜尋"
|
<input id="itinerary-search" type="search" aria-label="行程搜尋"
|
||||||
placeholder="搜尋地點、描述、標籤(例如:九份、夜市、Day 2)">
|
placeholder="搜尋地點、描述、標籤(例如:九份、夜市、Day 2)">
|
||||||
|
|
||||||
<main class="content-container map-layout">
|
<main id="taiwan" class="content-container map-layout">
|
||||||
<!-- 備註:地圖區固定使用你的 Google My Maps iframe。
|
<!-- 備註:地圖區固定使用你的 Google My Maps iframe。
|
||||||
這裡不改地圖資料來源,右側列表只負責敘事與導覽。 -->
|
這裡不改地圖資料來源,右側列表只負責敘事與導覽。 -->
|
||||||
<section class="map-sticky">
|
<section class="map-sticky">
|
||||||
<h2 class="map-title">水晶男孩台灣行程地圖</h2>
|
<h2 class="map-title">水晶男孩台灣行程地圖</h2>
|
||||||
<iframe id="member-map" title="SECHSKIES 踩點地圖" loading="lazy" referrerpolicy="no-referrer-when-downgrade"
|
<iframe id="member-map" title="SECHSKIES 踩點地圖" loading="lazy" referrerpolicy="no-referrer-when-downgrade"
|
||||||
src="https://www.google.com/maps/d/embed?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw&hl=zh-TW&ehbc=2E312F">
|
src="https://www.google.com/maps/d/embed?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI&ehbc=2E312F">
|
||||||
</iframe>
|
</iframe>
|
||||||
<a id="open-map-link" class="map-link" target="_blank"
|
<a id="open-map-link" class="map-link" target="_blank"
|
||||||
href="https://www.google.com/maps/d/u/0/viewer?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw">
|
href="https://www.google.com/maps/d/u/0/viewer?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI">
|
||||||
在 Google My Maps 開啟完整地圖
|
在 Google My Maps 開啟完整地圖
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
@@ -46,7 +98,141 @@
|
|||||||
<section class="itinerary-list">
|
<section class="itinerary-list">
|
||||||
<!-- 備註:每張卡的 data-* 是「細節面板的資料來源」。
|
<!-- 備註:每張卡的 data-* 是「細節面板的資料來源」。
|
||||||
你只要改 data-date/title/desc/quote/tag/link 和圖片,就會同步更新下方介紹。 -->
|
你只要改 data-date/title/desc/quote/tag/link 和圖片,就會同步更新下方介紹。 -->
|
||||||
<article class="polaroid-card active" data-member="kogo" data-date="Day 1" data-title="臺灣桃園國際機場"
|
<article class="polaroid-card active" data-member="eun" data-date="殷志源 Day 1" data-title="仁川國際機場"
|
||||||
|
data-desc="殷空少搭飛機去台灣高雄 Day 1 起點,從仁川出發。"
|
||||||
|
data-quote="高雄,我們來了。" data-tag="#殷志源 #Day1 #出發"
|
||||||
|
data-link="https://maps.google.com/?q=仁川國際機場">
|
||||||
|
<div class="photo-frame">
|
||||||
|
<img src="https://picsum.photos/seed/eun-khh-day1-1/640/420" alt="殷志源高雄行程節目截圖-仁川國際機場">
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<span class="date">殷志源 Day 1</span>
|
||||||
|
<h3>仁川國際機場</h3>
|
||||||
|
<p class="description">殷志源高雄行程第一站。</p>
|
||||||
|
<div class="tag">#殷志源 #Day1</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 1" data-title="高雄國際機場"
|
||||||
|
data-desc="抵達高雄,正式開始在地行程。"
|
||||||
|
data-quote="落地就是旅行模式開啟。" data-tag="#殷志源 #Day1 #高雄"
|
||||||
|
data-link="https://maps.google.com/?q=高雄國際機場">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day1-2/640/420" alt="殷志源高雄行程節目截圖-高雄國際機場"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 1</span><h3>高雄國際機場</h3><p class="description">殷志源高雄行程第二站。</p><div class="tag">#殷志源 #Day1</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 1" data-title="星巴克小港國際站門市"
|
||||||
|
data-desc="機場周邊補給點,為 Day 1 暖身。"
|
||||||
|
data-quote="先來一杯,狀態就到位。" data-tag="#殷志源 #Day1 #咖啡"
|
||||||
|
data-link="https://maps.google.com/?q=星巴克小港國際站門市">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day1-3/640/420" alt="殷志源高雄行程節目截圖-星巴克小港國際站門市"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 1</span><h3>星巴克小港國際站門市</h3><p class="description">殷志源高雄行程第三站。</p><div class="tag">#殷志源 #Day1</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 1" data-title="元帝廟北極亭"
|
||||||
|
data-desc="在地信仰文化路線,感受高雄生活節奏。"
|
||||||
|
data-quote="走進廟埕,城市的日常就有了溫度。" data-tag="#殷志源 #Day1 #文化"
|
||||||
|
data-link="https://maps.google.com/?q=元帝廟北極亭">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day1-4/640/420" alt="殷志源高雄行程節目截圖-元帝廟北極亭"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 1</span><h3>元帝廟北極亭</h3><p class="description">殷志源高雄行程第四站。</p><div class="tag">#殷志源 #Day1</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 1" data-title="桃子園餐廳"
|
||||||
|
data-desc="Day 1 用餐點,銜接下一天行程。"
|
||||||
|
data-quote="每一站都要有好吃的收尾。" data-tag="#殷志源 #Day1 #美食"
|
||||||
|
data-link="https://maps.google.com/?q=桃子園餐廳">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day1-5/640/420" alt="殷志源高雄行程節目截圖-桃子園餐廳"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 1</span><h3>桃子園餐廳</h3><p class="description">殷志源高雄行程第五站。</p><div class="tag">#殷志源 #Day1</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="哈囉市場"
|
||||||
|
data-desc="Day 2 從市場開始,走進高雄在地日常。"
|
||||||
|
data-quote="市場最能看見一座城市的生活感。" data-tag="#殷志源 #Day2 #市場"
|
||||||
|
data-link="https://maps.google.com/?q=哈囉市場">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-1/640/420" alt="殷志源高雄行程節目截圖-哈囉市場"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>哈囉市場</h3><p class="description">殷志源高雄行程 Day 2 第一站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="蓮池潭"
|
||||||
|
data-desc="高雄經典景點,白天景色與步行路線都很適合取景。"
|
||||||
|
data-quote="每一步都有風景可以拍。" data-tag="#殷志源 #Day2 #景點"
|
||||||
|
data-link="https://maps.google.com/?q=蓮池潭">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-2/640/420" alt="殷志源高雄行程節目截圖-蓮池潭"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>蓮池潭</h3><p class="description">殷志源高雄行程 Day 2 第二站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="龍虎塔"
|
||||||
|
data-desc="蓮池潭代表地標,適合搭配導覽與拍照段落。"
|
||||||
|
data-quote="高雄的經典場景之一。" data-tag="#殷志源 #Day2 #地標"
|
||||||
|
data-link="https://maps.google.com/?q=龍虎塔">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-3/640/420" alt="殷志源高雄行程節目截圖-龍虎塔"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>龍虎塔</h3><p class="description">殷志源高雄行程 Day 2 第三站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="輕軌高雄展覽館站(新光碼頭)"
|
||||||
|
data-desc="港區路線轉乘點,串接後續海線行程。"
|
||||||
|
data-quote="搭上輕軌,城市風景一路展開。" data-tag="#殷志源 #Day2 #輕軌"
|
||||||
|
data-link="https://maps.google.com/?q=輕軌高雄展覽館站(新光碼頭)">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-4/640/420" alt="殷志源高雄行程節目截圖-輕軌高雄展覽館站"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>輕軌高雄展覽館站(新光碼頭)</h3><p class="description">殷志源高雄行程 Day 2 第四站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="捷運哈瑪星站(輕軌哈瑪星站)"
|
||||||
|
data-desc="山海交界的人氣轉運點,步行動線完整。"
|
||||||
|
data-quote="到了哈瑪星,海港味就很濃。" data-tag="#殷志源 #Day2 #捷運"
|
||||||
|
data-link="https://maps.google.com/?q=捷運哈瑪星站">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-5/640/420" alt="殷志源高雄行程節目截圖-捷運哈瑪星站"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>捷運哈瑪星站(輕軌哈瑪星站)</h3><p class="description">殷志源高雄行程 Day 2 第五站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="仁武烤鴨"
|
||||||
|
data-desc="高雄人氣美食站,安排在中段補給。"
|
||||||
|
data-quote="好吃到會想直接再外帶一份。" data-tag="#殷志源 #Day2 #美食"
|
||||||
|
data-link="https://maps.google.com/?q=仁武烤鴨">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-6/640/420" alt="殷志源高雄行程節目截圖-仁武烤鴨"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>仁武烤鴨</h3><p class="description">殷志源高雄行程 Day 2 第六站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="握咖啡西子灣店(總店)"
|
||||||
|
data-desc="海邊咖啡節奏,適合休息和訪談。"
|
||||||
|
data-quote="在西子灣,時間會慢下來。" data-tag="#殷志源 #Day2 #咖啡"
|
||||||
|
data-link="https://maps.google.com/?q=握咖啡西子灣店(總店)">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-7/640/420" alt="殷志源高雄行程節目截圖-握咖啡西子灣店"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>握咖啡西子灣店(總店)</h3><p class="description">殷志源高雄行程 Day 2 第七站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="鼓山輪渡站"
|
||||||
|
data-desc="前往旗津的重要交通節點。"
|
||||||
|
data-quote="坐上渡輪,旅程感直接拉滿。" data-tag="#殷志源 #Day2 #輪渡"
|
||||||
|
data-link="https://maps.google.com/?q=鼓山輪渡站">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-8/640/420" alt="殷志源高雄行程節目截圖-鼓山輪渡站"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>鼓山輪渡站</h3><p class="description">殷志源高雄行程 Day 2 第八站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="旗津輪渡站"
|
||||||
|
data-desc="抵達旗津,展開海岸線路段。"
|
||||||
|
data-quote="到了旗津,風都不一樣。" data-tag="#殷志源 #Day2 #旗津"
|
||||||
|
data-link="https://maps.google.com/?q=旗津輪渡站">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-9/640/420" alt="殷志源高雄行程節目截圖-旗津輪渡站"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>旗津輪渡站</h3><p class="description">殷志源高雄行程 Day 2 第九站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="樂騎腳踏車、電動車、遊園車(旗津)"
|
||||||
|
data-desc="旗津移動工具租借點(和隔壁不是同一間)。"
|
||||||
|
data-quote="騎上車,海邊路線更完整。" data-tag="#殷志源 #Day2 #旗津"
|
||||||
|
data-link="https://maps.google.com/?q=樂騎腳踏車 旗津">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-10/640/420" alt="殷志源高雄行程節目截圖-樂騎腳踏車"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>樂騎腳踏車、電動車、遊園車(旗津)</h3><p class="description">殷志源高雄行程 Day 2 第十站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="旗津彩虹教堂"
|
||||||
|
data-desc="旗津拍照地標之一。"
|
||||||
|
data-quote="彩虹教堂是旗津必拍清單。" data-tag="#殷志源 #Day2 #旗津"
|
||||||
|
data-link="https://maps.google.com/?q=旗津彩虹教堂">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-11/640/420" alt="殷志源高雄行程節目截圖-旗津彩虹教堂"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>旗津彩虹教堂</h3><p class="description">殷志源高雄行程 Day 2 第十一站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="旗津貝殼館"
|
||||||
|
data-desc="旗津主題展點,補足海線內容。"
|
||||||
|
data-quote="一站一站把海線故事拼起來。" data-tag="#殷志源 #Day2 #旗津"
|
||||||
|
data-link="https://maps.google.com/?q=旗津貝殼館">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-12/640/420" alt="殷志源高雄行程節目截圖-旗津貝殼館"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>旗津貝殼館</h3><p class="description">殷志源高雄行程 Day 2 第十二站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
<article class="polaroid-card" data-member="eun" data-date="殷志源 Day 2" data-title="海忠寶活海產店"
|
||||||
|
data-desc="高雄海線行程收尾美食站。"
|
||||||
|
data-quote="最後用海鮮把今天完美收尾。" data-tag="#殷志源 #Day2 #美食"
|
||||||
|
data-link="https://maps.google.com/?q=海忠寶活海產店">
|
||||||
|
<div class="photo-frame"><img src="https://picsum.photos/seed/eun-khh-day2-13/640/420" alt="殷志源高雄行程節目截圖-海忠寶活海產店"></div>
|
||||||
|
<div class="card-content"><span class="date">殷志源 Day 2</span><h3>海忠寶活海產店</h3><p class="description">殷志源高雄行程 Day 2 第十三站。</p><div class="tag">#殷志源 #Day2</div></div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="polaroid-card" data-member="kogo" data-date="高志溶 Day 1" data-title="臺灣桃園國際機場"
|
||||||
data-desc="高高父子遊台灣 Day 1 首站,從桃園機場正式開啟三天行程。"
|
data-desc="高高父子遊台灣 Day 1 首站,從桃園機場正式開啟三天行程。"
|
||||||
data-quote="旅程從落地那一刻就開始了。" data-tag="#高高父子遊台灣 #Day1 #機場"
|
data-quote="旅程從落地那一刻就開始了。" data-tag="#高高父子遊台灣 #Day1 #機場"
|
||||||
data-link="https://maps.google.com/?q=臺灣桃園國際機場">
|
data-link="https://maps.google.com/?q=臺灣桃園國際機場">
|
||||||
@@ -54,7 +240,7 @@
|
|||||||
<img src="https://picsum.photos/seed/day1-airport/640/420" alt="高高父子遊台灣節目截圖-臺灣桃園國際機場">
|
<img src="https://picsum.photos/seed/day1-airport/640/420" alt="高高父子遊台灣節目截圖-臺灣桃園國際機場">
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<span class="date">Day 1</span>
|
<span class="date">高志溶 Day 1</span>
|
||||||
<h3>臺灣桃園國際機場</h3>
|
<h3>臺灣桃園國際機場</h3>
|
||||||
<p class="description">高高父子遊台灣 Day 1 第一站。</p>
|
<p class="description">高高父子遊台灣 Day 1 第一站。</p>
|
||||||
<div class="tag">#高高父子遊台灣 #Day1</div>
|
<div class="tag">#高高父子遊台灣 #Day1</div>
|
||||||
@@ -332,167 +518,16 @@
|
|||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
<footer id="contact">
|
||||||
|
<div id="global"></div>
|
||||||
|
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||||
|
<a href="https://jekkinoopy.github.io/Portfolio/" class="studio-link" target="_blank">
|
||||||
|
Design by <strong>Jekkinoopy Studio</strong>
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script src="map.js"></script>
|
||||||
(function () {
|
<script src="portal-nav.js"></script>
|
||||||
const tabs = Array.from(document.querySelectorAll(".tab-btn"));
|
|
||||||
const cards = Array.from(document.querySelectorAll(".polaroid-card"));
|
|
||||||
const searchInput = document.getElementById("itinerary-search");
|
|
||||||
const itineraryList = document.querySelector(".itinerary-list");
|
|
||||||
const detailPanel = document.getElementById("detail-panel");
|
|
||||||
const detailDate = document.getElementById("detail-date");
|
|
||||||
const detailTitle = document.getElementById("detail-title");
|
|
||||||
const detailDesc = document.getElementById("detail-desc");
|
|
||||||
const detailQuote = document.getElementById("detail-quote");
|
|
||||||
const detailTag = document.getElementById("detail-tag");
|
|
||||||
const detailLink = document.getElementById("detail-link");
|
|
||||||
const detailImage = document.getElementById("detail-image");
|
|
||||||
const dayGroups = new Map();
|
|
||||||
|
|
||||||
let currentMember = "all";
|
|
||||||
let currentKeyword = "";
|
|
||||||
|
|
||||||
function getCardSearchText(card) {
|
|
||||||
return [
|
|
||||||
card.dataset.date || "",
|
|
||||||
card.dataset.title || "",
|
|
||||||
card.dataset.desc || "",
|
|
||||||
card.dataset.tag || "",
|
|
||||||
].join(" ").toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createDayGroup(dayLabel) {
|
|
||||||
const group = document.createElement("section");
|
|
||||||
group.className = "day-group";
|
|
||||||
group.dataset.day = dayLabel;
|
|
||||||
|
|
||||||
const toggle = document.createElement("button");
|
|
||||||
toggle.type = "button";
|
|
||||||
toggle.className = "day-toggle";
|
|
||||||
toggle.setAttribute("aria-expanded", "false");
|
|
||||||
toggle.innerHTML = "<span>" + dayLabel + "</span><i class='fa-solid fa-chevron-down'></i>";
|
|
||||||
|
|
||||||
const body = document.createElement("div");
|
|
||||||
body.className = "day-cards";
|
|
||||||
body.style.display = "none";
|
|
||||||
|
|
||||||
group.appendChild(toggle);
|
|
||||||
group.appendChild(body);
|
|
||||||
itineraryList.insertBefore(group, detailPanel);
|
|
||||||
dayGroups.set(dayLabel, { group, toggle, body });
|
|
||||||
return dayGroups.get(dayLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setDayExpanded(dayGroup, shouldExpand) {
|
|
||||||
dayGroup.toggle.setAttribute("aria-expanded", shouldExpand ? "true" : "false");
|
|
||||||
dayGroup.body.style.display = shouldExpand ? "grid" : "none";
|
|
||||||
dayGroup.group.classList.toggle("expanded", shouldExpand);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeDayGroups() {
|
|
||||||
cards.forEach((card) => {
|
|
||||||
const dayLabel = card.dataset.date || "未分類";
|
|
||||||
const dayGroup = dayGroups.get(dayLabel) || createDayGroup(dayLabel);
|
|
||||||
dayGroup.body.appendChild(card);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateDayGroupVisibility() {
|
|
||||||
dayGroups.forEach(({ group, body, toggle }) => {
|
|
||||||
const visibleCards = Array.from(body.querySelectorAll(".polaroid-card")).filter((card) => card.style.display !== "none");
|
|
||||||
group.style.display = visibleCards.length ? "" : "none";
|
|
||||||
if (!visibleCards.length) {
|
|
||||||
setDayExpanded({ group, toggle, body }, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureExpandedForCard(card) {
|
|
||||||
const dayGroup = dayGroups.get(card.dataset.date || "未分類");
|
|
||||||
if (!dayGroup) return;
|
|
||||||
setDayExpanded(dayGroup, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveCard(card, options = {}) {
|
|
||||||
const { expandDay = true } = options;
|
|
||||||
cards.forEach((item) => item.classList.remove("active"));
|
|
||||||
card.classList.add("active");
|
|
||||||
if (expandDay) {
|
|
||||||
ensureExpandedForCard(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
detailDate.textContent = card.dataset.date || "";
|
|
||||||
detailTitle.textContent = card.dataset.title || "";
|
|
||||||
detailDesc.textContent = card.dataset.desc || "";
|
|
||||||
detailQuote.textContent = "「" + (card.dataset.quote || "") + "」";
|
|
||||||
detailTag.textContent = card.dataset.tag || "";
|
|
||||||
detailLink.href = card.dataset.link || "#";
|
|
||||||
detailImage.src = card.querySelector("img").src;
|
|
||||||
detailImage.alt = "節目截圖 - " + (card.dataset.title || "行程地點");
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyFilter() {
|
|
||||||
let firstVisible = null;
|
|
||||||
cards.forEach((card) => {
|
|
||||||
const matchedMember = currentMember === "all" || card.dataset.member === currentMember;
|
|
||||||
const matchedKeyword = !currentKeyword || getCardSearchText(card).includes(currentKeyword);
|
|
||||||
const matched = matchedMember && matchedKeyword;
|
|
||||||
card.style.display = matched ? "" : "none";
|
|
||||||
if (matched && !firstVisible) firstVisible = card;
|
|
||||||
});
|
|
||||||
updateDayGroupVisibility();
|
|
||||||
const activeVisibleCard = cards.find((card) => card.classList.contains("active") && card.style.display !== "none");
|
|
||||||
const fallbackCard = activeVisibleCard || firstVisible;
|
|
||||||
if (fallbackCard) {
|
|
||||||
// 保持預設收合:篩選/初始化時只更新細節,不主動展開 Day 群組。
|
|
||||||
setActiveCard(fallbackCard, { expandDay: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs.forEach((tab) => {
|
|
||||||
tab.addEventListener("click", () => {
|
|
||||||
tabs.forEach((item) => {
|
|
||||||
item.classList.remove("active");
|
|
||||||
item.setAttribute("aria-pressed", "false");
|
|
||||||
});
|
|
||||||
tab.classList.add("active");
|
|
||||||
tab.setAttribute("aria-pressed", "true");
|
|
||||||
currentMember = tab.dataset.member;
|
|
||||||
applyFilter();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (searchInput) {
|
|
||||||
searchInput.addEventListener("input", (event) => {
|
|
||||||
currentKeyword = event.target.value.trim().toLowerCase();
|
|
||||||
applyFilter();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
itineraryList.addEventListener("click", (event) => {
|
|
||||||
const toggle = event.target.closest(".day-toggle");
|
|
||||||
if (!toggle) return;
|
|
||||||
const group = toggle.closest(".day-group");
|
|
||||||
if (!group) return;
|
|
||||||
const dayGroup = dayGroups.get(group.dataset.day);
|
|
||||||
if (!dayGroup) return;
|
|
||||||
const isExpanded = dayGroup.toggle.getAttribute("aria-expanded") === "true";
|
|
||||||
setDayExpanded(dayGroup, !isExpanded);
|
|
||||||
});
|
|
||||||
|
|
||||||
cards.forEach((card) => {
|
|
||||||
card.addEventListener("click", () => {
|
|
||||||
setActiveCard(card, { expandDay: true });
|
|
||||||
if (window.innerWidth < 920) {
|
|
||||||
detailPanel.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
initializeDayGroups();
|
|
||||||
applyFilter();
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
(() => {
|
||||||
|
const canvas = document.getElementById("particles");
|
||||||
|
if (canvas) {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
let particles = [];
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Particle {
|
||||||
|
constructor() {
|
||||||
|
this.x = Math.random() * canvas.width;
|
||||||
|
this.y = Math.random() * canvas.height;
|
||||||
|
this.size = Math.random() * 4 + 1;
|
||||||
|
this.speedX = Math.random() * 0.5 - 0.25;
|
||||||
|
this.speedY = Math.random() * 0.5 + 0.2;
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY;
|
||||||
|
if (this.y > canvas.height) this.y = 0;
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
ctx.fillStyle = "#FFDD00";
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initParticles() {
|
||||||
|
particles = [];
|
||||||
|
for (let i = 0; i < 80; i += 1) {
|
||||||
|
particles.push(new Particle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animateParticles() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (const particle of particles) {
|
||||||
|
particle.update();
|
||||||
|
particle.draw();
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animateParticles);
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas();
|
||||||
|
initParticles();
|
||||||
|
animateParticles();
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
resizeCanvas();
|
||||||
|
initParticles();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = Array.from(document.querySelectorAll(".tab-btn"));
|
||||||
|
const cards = Array.from(document.querySelectorAll(".polaroid-card"));
|
||||||
|
const searchInput = document.getElementById("itinerary-search");
|
||||||
|
const itineraryList = document.querySelector(".itinerary-list");
|
||||||
|
const detailPanel = document.getElementById("detail-panel");
|
||||||
|
const detailDate = document.getElementById("detail-date");
|
||||||
|
const detailTitle = document.getElementById("detail-title");
|
||||||
|
const detailDesc = document.getElementById("detail-desc");
|
||||||
|
const detailQuote = document.getElementById("detail-quote");
|
||||||
|
const detailTag = document.getElementById("detail-tag");
|
||||||
|
const detailLink = document.getElementById("detail-link");
|
||||||
|
const detailImage = document.getElementById("detail-image");
|
||||||
|
const memberMapFrame = document.getElementById("member-map");
|
||||||
|
const openMapLink = document.getElementById("open-map-link");
|
||||||
|
const dayGroups = new Map();
|
||||||
|
|
||||||
|
let currentMember = "all";
|
||||||
|
let currentKeyword = "";
|
||||||
|
const memberMaps = {
|
||||||
|
eun: {
|
||||||
|
embed: "https://www.google.com/maps/d/embed?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI&ehbc=2E312F",
|
||||||
|
open: "https://www.google.com/maps/d/u/0/viewer?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI"
|
||||||
|
},
|
||||||
|
ko: {
|
||||||
|
embed: "https://www.google.com/maps/d/embed?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw&hl=zh-TW&ehbc=2E312F",
|
||||||
|
open: "https://www.google.com/maps/d/u/0/viewer?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const memberTripPrefix = {
|
||||||
|
ko: "高高父子遊台灣",
|
||||||
|
eun: "殷空少搭飛機去台灣高雄"
|
||||||
|
};
|
||||||
|
const memberSortOrder = { ko: 0, eun: 1 };
|
||||||
|
|
||||||
|
function normalizeMember(member) {
|
||||||
|
if (member === "kogo") return "ko";
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMemberLabel(member) {
|
||||||
|
const normalized = normalizeMember(member);
|
||||||
|
if (normalized === "eun") return "殷志源";
|
||||||
|
if (normalized === "ko") return "高志溶";
|
||||||
|
return "未分類";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDayToken(rawDate) {
|
||||||
|
const match = String(rawDate || "").match(/Day\s*(\d+)/i);
|
||||||
|
if (!match) return String(rawDate || "未分類");
|
||||||
|
return "Day " + match[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroupLabel(card) {
|
||||||
|
const date = getDayToken(card.dataset.date || "未分類");
|
||||||
|
const normalized = normalizeMember(card.dataset.member || "");
|
||||||
|
const prefix = memberTripPrefix[normalized] || getMemberLabel(normalized);
|
||||||
|
return prefix + "_" + date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMapByMember(member) {
|
||||||
|
const normalized = normalizeMember(member);
|
||||||
|
const mapConfig = memberMaps[normalized];
|
||||||
|
if (!mapConfig) return;
|
||||||
|
memberMapFrame.src = mapConfig.embed;
|
||||||
|
openMapLink.href = mapConfig.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCardSearchText(card) {
|
||||||
|
return [
|
||||||
|
card.dataset.date || "",
|
||||||
|
card.dataset.title || "",
|
||||||
|
card.dataset.desc || "",
|
||||||
|
card.dataset.tag || "",
|
||||||
|
].join(" ").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDayGroup(dayLabel) {
|
||||||
|
const group = document.createElement("section");
|
||||||
|
group.className = "day-group";
|
||||||
|
group.dataset.day = dayLabel;
|
||||||
|
|
||||||
|
const toggle = document.createElement("button");
|
||||||
|
toggle.type = "button";
|
||||||
|
toggle.className = "day-toggle";
|
||||||
|
toggle.setAttribute("aria-expanded", "false");
|
||||||
|
toggle.innerHTML = "<span>" + dayLabel + "</span><i class='fa-solid fa-chevron-down'></i>";
|
||||||
|
|
||||||
|
const body = document.createElement("div");
|
||||||
|
body.className = "day-cards";
|
||||||
|
body.style.display = "none";
|
||||||
|
|
||||||
|
group.appendChild(toggle);
|
||||||
|
group.appendChild(body);
|
||||||
|
itineraryList.insertBefore(group, detailPanel);
|
||||||
|
dayGroups.set(dayLabel, { group, toggle, body });
|
||||||
|
return dayGroups.get(dayLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDayExpanded(dayGroup, shouldExpand) {
|
||||||
|
dayGroup.toggle.setAttribute("aria-expanded", shouldExpand ? "true" : "false");
|
||||||
|
dayGroup.body.style.display = shouldExpand ? "grid" : "none";
|
||||||
|
dayGroup.group.classList.toggle("expanded", shouldExpand);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeDayGroups() {
|
||||||
|
const sortedCards = [...cards].sort((a, b) => {
|
||||||
|
const memberA = normalizeMember(a.dataset.member || "");
|
||||||
|
const memberB = normalizeMember(b.dataset.member || "");
|
||||||
|
const memberDiff = (memberSortOrder[memberA] ?? 99) - (memberSortOrder[memberB] ?? 99);
|
||||||
|
if (memberDiff !== 0) return memberDiff;
|
||||||
|
|
||||||
|
const dayA = Number((getDayToken(a.dataset.date).match(/\d+/) || [999])[0]);
|
||||||
|
const dayB = Number((getDayToken(b.dataset.date).match(/\d+/) || [999])[0]);
|
||||||
|
return dayA - dayB;
|
||||||
|
});
|
||||||
|
|
||||||
|
sortedCards.forEach((card) => {
|
||||||
|
const dayLabel = getGroupLabel(card);
|
||||||
|
const dayGroup = dayGroups.get(dayLabel) || createDayGroup(dayLabel);
|
||||||
|
dayGroup.body.appendChild(card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDayGroupVisibility() {
|
||||||
|
dayGroups.forEach(({ group, body, toggle }) => {
|
||||||
|
const visibleCards = Array.from(body.querySelectorAll(".polaroid-card")).filter((card) => card.style.display !== "none");
|
||||||
|
group.style.display = visibleCards.length ? "" : "none";
|
||||||
|
if (!visibleCards.length) {
|
||||||
|
setDayExpanded({ group, toggle, body }, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureExpandedForCard(card) {
|
||||||
|
const dayGroup = dayGroups.get(getGroupLabel(card));
|
||||||
|
if (!dayGroup) return;
|
||||||
|
setDayExpanded(dayGroup, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveCard(card, options = {}) {
|
||||||
|
const { expandDay = true } = options;
|
||||||
|
cards.forEach((item) => item.classList.remove("active"));
|
||||||
|
card.classList.add("active");
|
||||||
|
if (expandDay) {
|
||||||
|
ensureExpandedForCard(card);
|
||||||
|
}
|
||||||
|
updateMapByMember(card.dataset.member || "all");
|
||||||
|
|
||||||
|
detailDate.textContent = card.dataset.date || "";
|
||||||
|
detailTitle.textContent = card.dataset.title || "";
|
||||||
|
detailDesc.textContent = card.dataset.desc || "";
|
||||||
|
detailQuote.textContent = "「" + (card.dataset.quote || "") + "」";
|
||||||
|
detailTag.textContent = card.dataset.tag || "";
|
||||||
|
detailLink.href = card.dataset.link || "#";
|
||||||
|
detailImage.src = card.querySelector("img").src;
|
||||||
|
detailImage.alt = "節目截圖 - " + (card.dataset.title || "行程地點");
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilter() {
|
||||||
|
let firstVisible = null;
|
||||||
|
cards.forEach((card) => {
|
||||||
|
const cardMember = normalizeMember(card.dataset.member || "");
|
||||||
|
const matchedMember = currentMember === "all" || cardMember === currentMember;
|
||||||
|
const matchedKeyword = !currentKeyword || getCardSearchText(card).includes(currentKeyword);
|
||||||
|
const matched = matchedMember && matchedKeyword;
|
||||||
|
card.style.display = matched ? "" : "none";
|
||||||
|
if (matched && !firstVisible) firstVisible = card;
|
||||||
|
});
|
||||||
|
updateDayGroupVisibility();
|
||||||
|
const activeVisibleCard = cards.find((card) => card.classList.contains("active") && card.style.display !== "none");
|
||||||
|
const fallbackCard = activeVisibleCard || firstVisible;
|
||||||
|
if (fallbackCard) {
|
||||||
|
setActiveCard(fallbackCard, { expandDay: false });
|
||||||
|
} else if (currentMember !== "all") {
|
||||||
|
updateMapByMember(currentMember);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tabs.forEach((tab) => {
|
||||||
|
tab.addEventListener("click", () => {
|
||||||
|
tabs.forEach((item) => {
|
||||||
|
item.classList.remove("active");
|
||||||
|
item.setAttribute("aria-pressed", "false");
|
||||||
|
});
|
||||||
|
tab.classList.add("active");
|
||||||
|
tab.setAttribute("aria-pressed", "true");
|
||||||
|
currentMember = normalizeMember(tab.dataset.member || "all");
|
||||||
|
applyFilter();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.addEventListener("input", (event) => {
|
||||||
|
currentKeyword = event.target.value.trim().toLowerCase();
|
||||||
|
applyFilter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
itineraryList.addEventListener("click", (event) => {
|
||||||
|
const toggle = event.target.closest(".day-toggle");
|
||||||
|
if (!toggle) return;
|
||||||
|
const group = toggle.closest(".day-group");
|
||||||
|
if (!group) return;
|
||||||
|
const dayGroup = dayGroups.get(group.dataset.day);
|
||||||
|
if (!dayGroup) return;
|
||||||
|
const isExpanded = dayGroup.toggle.getAttribute("aria-expanded") === "true";
|
||||||
|
setDayExpanded(dayGroup, !isExpanded);
|
||||||
|
});
|
||||||
|
|
||||||
|
cards.forEach((card) => {
|
||||||
|
card.addEventListener("click", () => {
|
||||||
|
setActiveCard(card, { expandDay: true });
|
||||||
|
if (window.innerWidth < 920) {
|
||||||
|
detailPanel.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
initializeDayGroups();
|
||||||
|
applyFilter();
|
||||||
|
})();
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
(() => {
|
||||||
|
const canvas = document.getElementById("particles");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
let particles = [];
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Particle {
|
||||||
|
constructor() {
|
||||||
|
this.x = Math.random() * canvas.width;
|
||||||
|
this.y = Math.random() * canvas.height;
|
||||||
|
this.size = Math.random() * 4 + 1;
|
||||||
|
this.speedX = Math.random() * 0.5 - 0.25;
|
||||||
|
this.speedY = Math.random() * 0.5 + 0.2;
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
this.x += this.speedX;
|
||||||
|
this.y += this.speedY;
|
||||||
|
if (this.y > canvas.height) this.y = 0;
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
ctx.fillStyle = "#FFDD00";
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initParticles() {
|
||||||
|
particles = [];
|
||||||
|
for (let i = 0; i < 80; i += 1) {
|
||||||
|
particles.push(new Particle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animateParticles() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (const particle of particles) {
|
||||||
|
particle.update();
|
||||||
|
particle.draw();
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animateParticles);
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas();
|
||||||
|
initParticles();
|
||||||
|
animateParticles();
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
resizeCanvas();
|
||||||
|
initParticles();
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
(() => {
|
||||||
|
const navs = Array.from(document.querySelectorAll(".portal-nav"));
|
||||||
|
if (!navs.length) return;
|
||||||
|
|
||||||
|
const currentPage = window.location.pathname.split("/").pop() || "index.html";
|
||||||
|
|
||||||
|
navs.forEach((nav) => {
|
||||||
|
const items = Array.from(nav.querySelectorAll("li"));
|
||||||
|
const soonLinks = Array.from(nav.querySelectorAll('a[data-coming-soon="true"]'));
|
||||||
|
|
||||||
|
soonLinks.forEach((link) => {
|
||||||
|
link.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
items.forEach((item) => {
|
||||||
|
const trigger = item.querySelector(":scope > a");
|
||||||
|
const submenu = item.querySelector(":scope > .portal-submenu");
|
||||||
|
if (!trigger || !submenu) return;
|
||||||
|
|
||||||
|
let closeTimer = null;
|
||||||
|
|
||||||
|
const openItem = () => {
|
||||||
|
if (closeTimer) window.clearTimeout(closeTimer);
|
||||||
|
items.forEach((other) => {
|
||||||
|
if (other !== item) other.classList.remove("open");
|
||||||
|
});
|
||||||
|
item.classList.add("open");
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleClose = () => {
|
||||||
|
closeTimer = window.setTimeout(() => item.classList.remove("open"), 180);
|
||||||
|
};
|
||||||
|
|
||||||
|
item.addEventListener("mouseenter", openItem);
|
||||||
|
item.addEventListener("mouseleave", scheduleClose);
|
||||||
|
trigger.addEventListener("focus", openItem);
|
||||||
|
|
||||||
|
trigger.addEventListener("click", (event) => {
|
||||||
|
if (window.innerWidth <= 1024) {
|
||||||
|
event.preventDefault();
|
||||||
|
item.classList.toggle("open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
if (!nav.contains(event.target)) {
|
||||||
|
items.forEach((item) => item.classList.remove("open"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const topLevelLinks = Array.from(nav.querySelectorAll(":scope > ul > li > a[href]"));
|
||||||
|
topLevelLinks.forEach((link) => {
|
||||||
|
const href = link.getAttribute("href");
|
||||||
|
if (!href) return;
|
||||||
|
const [file] = href.split("#");
|
||||||
|
if (file === currentPage) {
|
||||||
|
link.classList.add("nav-current");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -103,6 +103,117 @@ nav a:hover {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.portal-nav li {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav {
|
||||||
|
position: relative;
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav .portal-submenu {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% - 2px);
|
||||||
|
left: 0;
|
||||||
|
min-width: 220px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
|
||||||
|
z-index: 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav .portal-submenu li {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav .portal-submenu a {
|
||||||
|
display: block;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #5f5f5f;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav .portal-submenu a:hover {
|
||||||
|
background: #fff8df;
|
||||||
|
color: #3a300a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav a.nav-current {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav>ul>li.coming-soon>a {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
color: #c8a66a !important;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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"] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portal-nav li.coming-soon>.portal-submenu {
|
||||||
|
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:focus-within>.portal-submenu,
|
||||||
|
.portal-nav li.open>.portal-submenu {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
#particles {
|
#particles {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -169,11 +280,18 @@ footer {
|
|||||||
|
|
||||||
/* 區塊容器 */
|
/* 區塊容器 */
|
||||||
.container {
|
.container {
|
||||||
max-width: 1000px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 40px 20px;
|
padding: 40px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -457,19 +575,136 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* map.html */
|
/* map.html */
|
||||||
|
.map-page .map-archive-header,
|
||||||
|
.map-page .portal-nav,
|
||||||
|
.map-page .member-tabs,
|
||||||
|
.map-page #itinerary-search,
|
||||||
|
.map-page .map-layout,
|
||||||
|
.map-page footer {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.concert-page .concert-archive-header,
|
||||||
|
.concert-page .portal-nav,
|
||||||
|
.concert-page .search-section,
|
||||||
|
.concert-page .concert-container,
|
||||||
|
.concert-page footer {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 0 14px;
|
||||||
|
padding: 0.8rem 100px;
|
||||||
|
background-color: var(--black);
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
overflow: visible;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 24px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul>li {
|
||||||
|
position: relative;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul>li>a {
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--primary);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 4px 2px;
|
||||||
|
border-bottom: 0;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul>li>a:hover,
|
||||||
|
.map-page .portal-nav>ul>li:focus-within>a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav .portal-submenu {
|
||||||
|
position: absolute;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
top: calc(100% + 8px);
|
||||||
|
min-width: 240px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
|
||||||
|
display: none;
|
||||||
|
gap: 6px;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul>li:hover .portal-submenu,
|
||||||
|
.map-page .portal-nav>ul>li:focus-within .portal-submenu {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav .portal-submenu a {
|
||||||
|
display: block;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
color: #5f5f5f;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav .portal-submenu a:hover {
|
||||||
|
background: #fff8df;
|
||||||
|
color: #3a300a;
|
||||||
|
}
|
||||||
|
|
||||||
.map-archive-header {
|
.map-archive-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
min-height: 100dvh;
|
||||||
|
background-image: url('img/header.jpg');
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 108%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 90px 20px 38px;
|
padding: 0 20px;
|
||||||
background: #fcfaf2;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-archive-header .main-title {
|
.map-archive-header .main-title {
|
||||||
font-size: clamp(2rem, 4.5vw, 3.2rem);
|
font-size: clamp(2rem, 4.5vw, 3.2rem);
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
color: #333;
|
color: var(--yellow);
|
||||||
letter-spacing: 8px;
|
letter-spacing: 6px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
text-shadow: 0 0 30px rgba(255, 221, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-archive-header .subtitle-wrap {
|
.map-archive-header .subtitle-wrap {
|
||||||
@@ -484,9 +719,9 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.map-archive-header .sub-title {
|
.map-archive-header .sub-title {
|
||||||
font-size: 0.96rem;
|
font-size: 0.92rem;
|
||||||
letter-spacing: 4px;
|
letter-spacing: 4px;
|
||||||
color: #8a8a8a;
|
color: #d4d4d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-layout {
|
.map-layout {
|
||||||
@@ -498,12 +733,13 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.member-tabs {
|
.member-tabs {
|
||||||
|
background: transparent;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
margin: 14px auto 14px;
|
margin: 18px auto 14px;
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
padding: 4px 20px;
|
padding: 4px 20px;
|
||||||
}
|
}
|
||||||
@@ -763,7 +999,8 @@ footer {
|
|||||||
|
|
||||||
@media (max-width: 920px) {
|
@media (max-width: 920px) {
|
||||||
.map-archive-header {
|
.map-archive-header {
|
||||||
padding: 76px 16px 30px;
|
background-size: cover;
|
||||||
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-archive-header .main-title {
|
.map-archive-header .main-title {
|
||||||
@@ -774,6 +1011,25 @@ footer {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav>ul {
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav {
|
||||||
|
padding: 0.8rem 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-page .portal-nav .portal-submenu {
|
||||||
|
position: static;
|
||||||
|
min-width: 0;
|
||||||
|
margin-top: 6px;
|
||||||
|
display: grid;
|
||||||
|
box-shadow: none;
|
||||||
|
background: #fffaf0;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
#itinerary-search {
|
#itinerary-search {
|
||||||
width: calc(100% - 28px);
|
width: calc(100% - 28px);
|
||||||
}
|
}
|
||||||
@@ -806,3 +1062,96 @@ footer {
|
|||||||
padding: 13px;
|
padding: 13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Chronicle (webcomic-like reader) */
|
||||||
|
.chronicle-controls {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 24px auto 10px;
|
||||||
|
padding: 0 14px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn {
|
||||||
|
border: 0;
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: #ffe9a8;
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn.active {
|
||||||
|
background: var(--primary);
|
||||||
|
color: #161616;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-reader {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto 24px;
|
||||||
|
padding: 0 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-chapter {
|
||||||
|
background: #fffdf6;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 24px 20px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-chapter h2 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
color: #252525;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-chapter p {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
line-height: 1.9;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-pager {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto 30px;
|
||||||
|
padding: 0 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chapter-indicator {
|
||||||
|
min-width: 64px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #f6d66f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-pager .btn {
|
||||||
|
border: 0;
|
||||||
|
background: #171717;
|
||||||
|
color: #fff2bf;
|
||||||
|
padding: 9px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chronicle-pager .btn:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.chronicle-chapter {
|
||||||
|
padding: 18px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user