fix add assets/並更新全站引用

This commit is contained in:
jekkinoopy committed 2026-05-14 09:20:10 +08:00
1 parent a6525fdf44
commit c278df23e1
107 files changed
+1726 -1720

No files matched your search

+2 -2
View File
@@ -7,10 +7,10 @@ alwaysApply: true
## 預設只做「被點名」的範圍 ## 預設只做「被點名」的範圍
- 使用者若只提某頁(例如 **`minister_ge.html`**)、某區塊、某句文案:**只改該處**,不順手改 `index.html`、`minister.html`、`portal-nav.js`、`style.css` 全站區、或 **`index.css`** 裡與首頁共用的規則。 - 使用者若只提某頁(例如 **`minister_ge.html`**)、某區塊、某句文案:**只改該處**,不順手改 `index.html`、`minister.html`、`assets/js/portal-nav.js`、`assets/css/style.css` 全站區、或 **`assets/css/index.css`** 裡與首頁共用的規則。
- **未寫到的檔案=不開、不刪、不重構**;需要動到時,先用**一句話**說明「為何必須動」並等使用者確認,或改在回覆裡列出將被波及的檔案請使用者選是否要做。 - **未寫到的檔案=不開、不刪、不重構**;需要動到時,先用**一句話**說明「為何必須動」並等使用者確認,或改在回覆裡列出將被波及的檔案請使用者選是否要做。
## 共用樣式(`style.css`、全站 class) ## 共用樣式(`assets/css/style.css`、全站 class)
- **禁止**因為某一頁要對齊視覺,就擅自改掉全站 class(例如 `.slogan-quote`、`.mark_b`、`section` 預設)在**其他頁**的呈現。 - **禁止**因為某一頁要對齊視覺,就擅自改掉全站 class(例如 `.slogan-quote`、`.mark_b`、`section` 預設)在**其他頁**的呈現。
- **金句已分流**:覺醒稿用 **`slogan-quote slogan-quote--awakening`**(副標語彙:雙線+中置小字),首頁使命稿用 **`slogan-quote slogan-quote--mission`**(獨立奶油卡);基底 **`.slogan-quote` 不帶視覺**,**禁止**再只改基底就套兩種金句。 - **金句已分流**:覺醒稿用 **`slogan-quote slogan-quote--awakening`**(副標語彙:雙線+中置小字),首頁使命稿用 **`slogan-quote slogan-quote--mission`**(獨立奶油卡);基底 **`.slogan-quote` 不帶視覺**,**禁止**再只改基底就套兩種金句。
+3 -3
View File
@@ -9,7 +9,7 @@ alwaysApply: true
- **不得**在未被使用者**明確要求**的情況下:把導覽連結從「籌備中/尚無開放」改成可點、更換 `href` 成真實頁面、從 `COMING_SOON_PAGES` 移除、或把錨點加入 `INDEX_NAV_OPEN_HASHES`。 - **不得**在未被使用者**明確要求**的情況下:把導覽連結從「籌備中/尚無開放」改成可點、更換 `href` 成真實頁面、從 `COMING_SOON_PAGES` 移除、或把錨點加入 `INDEX_NAV_OPEN_HASHES`。
- **不得**因為「內容已搬到某頁」就自行推論「導覽也應該開放」——導覽是否開放**只聽使用者口述**。 - **不得**因為「內容已搬到某頁」就自行推論「導覽也應該開放」——導覽是否開放**只聽使用者口述**。
- 若使用者只要求搬內容、刪檔、改站內某段文案,**預設不改** `portal-nav.js` 的開放狀態與連結目標。 - 若使用者只要求搬內容、刪檔、改站內某段文案,**預設不改** `assets/js/portal-nav.js` 的開放狀態與連結目標。
## 「傳奇的轉折」導覽(特別記牢) ## 「傳奇的轉折」導覽(特別記牢)
@@ -18,11 +18,11 @@ alwaysApply: true
## 實作前自檢 ## 實作前自檢
- 若變更會影響 `portal-nav.js`(`PORTAL_NAV_INNER_HTML`、`COMING_SOON_PAGES`、`INDEX_NAV_OPEN_HASHES`):**對照使用者原句**,確認每一項連結的開/關都有被明確交代。 - 若變更會影響 `assets/js/portal-nav.js`(`buildPortalNavInnerHTML`、`COMING_SOON_PAGES`、`INDEX_NAV_OPEN_HASHES`):**對照使用者原句**,確認每一項連結的開/關都有被明確交代。
## 名詞對齊(避免做錯檔) ## 名詞對齊(避免做錯檔)
- **頂部橫列導覽(常稱 navbar)**:`portal-nav.js` 注入的 `<nav class="portal-nav" data-portal-nav>`,每一頁頂端黑底那一條。**備份稿/未公開頁**除非使用者**明講要上這條**,否則不要寫進 `PORTAL_NAV_INNER_HTML`。 - **頂部橫列導覽(常稱 navbar)**:`assets/js/portal-nav.js` 注入的 `<nav class="portal-nav" data-portal-nav>`,每一頁頂端黑底那一條。**備份稿/未公開頁**除非使用者**明講要上這條**,否則不要寫進 `buildPortalNavInnerHTML` 模板。
- **全站頁面索引**:`site-guide.html`(自行開網址),用來列檔案與錨點;**不影響**頂欄是否出現該連結。使用者說「留在全站導覽」常指保留在 **site-guide** 或站內說明,**不等於**要掛進頂欄。 - **全站頁面索引**:`site-guide.html`(自行開網址),用來列檔案與錨點;**不影響**頂欄是否出現該連結。使用者說「留在全站導覽」常指保留在 **site-guide** 或站內說明,**不等於**要掛進頂欄。
(變更哪些檔、可否動共用 CSS:見 **`ai-change-boundaries.mdc`**。) (變更哪些檔、可否動共用 CSS:見 **`ai-change-boundaries.mdc`**。)
+10 -10
View File
@@ -1,10 +1,10 @@
# 變更檢查清單(工作區 vs `HEAD`) # 變更檢查清單(工作區 vs `HEAD`)
> **說明:** 此為對話當初「第一批」完整筆記存檔(五檔:`albums`(原 `archive`)/`index.css`/`index.html`/`style.css`/`portal-nav`)。**目前工作區是否仍為下列每一項,請以 `git diff` 與實際檔案為準**,本文不作為程式真值來源。 > **說明:** 此為對話當初「第一批」完整筆記存檔(五檔:`albums`(原 `archive`)/`assets/css/index.css`/`index.html`/`assets/css/style.css`/`assets/js/portal-nav`)。**目前工作區是否仍為下列每一項,請以 `git diff` 與實際檔案為準**,本文不作為程式真值來源。
本文依 **`git diff`** 對照 **`HEAD`** 整理,方便逐項核對;不含未在本 diff 出現之檔案或臆測內容。 本文依 **`git diff`** 對照 **`HEAD`** 整理,方便逐項核對;不含未在本 diff 出現之檔案或臆測內容。
**涉及檔案(5)**:`albums/albums.html`、`index.css`、`index.html`、`portal-nav.js`、`style.css` **涉及檔案(5)**:`albums/albums.html`、`assets/css/index.css`、`index.html`、`assets/js/portal-nav.js`、`assets/css/style.css`
**統計**:以 `git diff --stat` 為準(以下內容對應該批變更初版筆記)。 **統計**:以 `git diff --stat` 為準(以下內容對應該批變更初版筆記)。
--- ---
@@ -38,7 +38,7 @@
| 輝煌全盛期 | 1998 Road Fighter | `https://open.spotify.com/album/08TW1bmGzSg172Db8C2Bde` | | 輝煌全盛期 | 1998 Road Fighter | `https://open.spotify.com/album/08TW1bmGzSg172Db8C2Bde` |
| 輝煌全盛期 | 1999 Com' Back | `https://open.spotify.com/album/3XWtqLXDZycu7Q0BGofhiq` | | 輝煌全盛期 | 1999 Com' Back | `https://open.spotify.com/album/3XWtqLXDZycu7Q0BGofhiq` |
### 內嵌腳本(`</body>` 前,`portal-nav.js` 之後) ### 內嵌腳本(`</body>` 前,`assets/js/portal-nav.js` 之後)
- `querySelectorAll('tr.archive-row-spotify[data-spotify-url]')` 綁定: - `querySelectorAll('tr.archive-row-spotify[data-spotify-url]')` 綁定:
- **click**:若 `e.target.closest('a')` 則不處理;否則 `window.open(url, '_blank', 'noopener,noreferrer')` - **click**:若 `e.target.closest('a')` 則不處理;否則 `window.open(url, '_blank', 'noopener,noreferrer')`
@@ -46,7 +46,7 @@
--- ---
## 2. `index.css` ## 2. `assets/css/index.css`
### 新增選擇器(僅作用於 `.archive-discography` 內) ### 新增選擇器(僅作用於 `.archive-discography` 內)
@@ -75,11 +75,11 @@
### 相依性(請檢查) ### 相依性(請檢查)
- 頁面須已載入 Font Awesome(與現有 `<link>` 一致),否則圖示不顯示。 - 頁面須已載入 Font Awesome(與現有 `<link>` 一致),否則圖示不顯示。
- `extra/totoga2.html` 須存在;`extra/totoga2.js` 會辨識網址列 `#ebook` 並切換至電子書模式。 - `extra/totoga2.html` 須存在;`assets/js/totoga2.js` 會辨識網址列 `#ebook` 並切換至電子書模式。
--- ---
## 4. `style.css` ## 4. `assets/css/style.css`
### 區塊註解 ### 區塊註解
@@ -101,7 +101,7 @@
--- ---
## 5. `portal-nav.js` ## 5. `assets/js/portal-nav.js`
### 目的 ### 目的
@@ -124,9 +124,9 @@
1. **`albums/albums.html`**:每列空白處/封面/年份點擊 → 新分頁 Spotify 正確專輯;點列內本站連結 → 仍進本站、不開 Spotify。 1. **`albums/albums.html`**:每列空白處/封面/年份點擊 → 新分頁 Spotify 正確專輯;點列內本站連結 → 仍進本站、不開 Spotify。
2. **`albums/albums.html`**:鍵盤 Tab 聚焦列後 Enter/空白 → 開 Spotify;聚焦在 `<a>` 上時 Enter → 遵循連結。 2. **`albums/albums.html`**:鍵盤 Tab 聚焦列後 Enter/空白 → 開 Spotify;聚焦在 `<a>` 上時 Enter → 遵循連結。
3. **`index.html` + `style.css`**:2016 卡片外觀與 CTA 按鈕、`hover`、`focus-visible`、縮減動態偏好設定下手勢動畫關閉。 3. **`index.html` + `assets/css/style.css`**:2016 卡片外觀與 CTA 按鈕、`hover`、`focus-visible`、縮減動態偏好設定下手勢動畫關閉。
4. **`portal-nav.js`**:全站注入後選單無「消失的真相」;改 `true` 後該項回來。 4. **`assets/js/portal-nav.js`**:全站注入後選單無「消失的真相」;改 `true` 後該項回來。
5. **跨頁**:任意頁載入 `portal-nav.js` 後行為一致。 5. **跨頁**:任意頁載入 `assets/js/portal-nav.js` 後行為一致。
--- ---
+8 -8
View File
@@ -5,10 +5,10 @@
<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>水晶男孩|黃色留聲機</title> <title>水晶男孩|黃色留聲機</title>
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="../index.css"> <link rel="stylesheet" href="../assets/css/index.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">
<link rel="stylesheet" href="../tablet.css"> <link rel="stylesheet" href="../assets/css/tablet.css">
</head> </head>
<body> <body>
@@ -50,7 +50,7 @@
data-spotify-url="https://open.spotify.com/album/1Dijv8G0wnCN8PzFZoC8bN" data-spotify-url="https://open.spotify.com/album/1Dijv8G0wnCN8PzFZoC8bN"
aria-label="在 Spotify 開啟:THREE WORDS(2016 數位單曲)"> aria-label="在 Spotify 開啟:THREE WORDS(2016 數位單曲)">
<td class="album-cover-cell"> <td class="album-cover-cell">
<img src="../images/albums/2016.jpg" width="76" height="76" alt="2016 數位單曲 封面"> <img src="../assets/images/albums/2016.jpg" width="76" height="76" alt="2016 數位單曲 封面">
</td> </td>
<td>2016</td> <td>2016</td>
<td><a href="../extra/lyrics.html">數位單曲</a></td> <td><a href="../extra/lyrics.html">數位單曲</a></td>
@@ -60,7 +60,7 @@
data-spotify-url="https://open.spotify.com/album/5f2LzIFxljQF4FH7w3rXcQ" data-spotify-url="https://open.spotify.com/album/5f2LzIFxljQF4FH7w3rXcQ"
aria-label="在 Spotify 開啟:ANOTHER LIGHT"> aria-label="在 Spotify 開啟:ANOTHER LIGHT">
<td class="album-cover-cell"> <td class="album-cover-cell">
<img src="../images/albums/2017.jpg" width="76" height="76" alt="2017 ANOTHER LIGHT 封面"> <img src="../assets/images/albums/2017.jpg" width="76" height="76" alt="2017 ANOTHER LIGHT 封面">
</td> </td>
<td>2017</td> <td>2017</td>
<td><a href="../concert/concert.html#stage-now">ANOTHER LIGHT</a></td> <td><a href="../concert/concert.html#stage-now">ANOTHER LIGHT</a></td>
@@ -70,7 +70,7 @@
data-spotify-url="https://open.spotify.com/album/7vqIRL00YfTtuO0sSAK3Uv" data-spotify-url="https://open.spotify.com/album/7vqIRL00YfTtuO0sSAK3Uv"
aria-label="在 Spotify 開啟:ALL FOR YOU"> aria-label="在 Spotify 開啟:ALL FOR YOU">
<td class="album-cover-cell"> <td class="album-cover-cell">
<img src="../images/albums/2020.jpg" width="76" height="76" alt="2020 ALL FOR YOU 封面"> <img src="../assets/images/albums/2020.jpg" width="76" height="76" alt="2020 ALL FOR YOU 封面">
</td> </td>
<td>2020</td> <td>2020</td>
<td><a href="../concert/concert.html#stage-now">ALL FOR YOU</a></td> <td><a href="../concert/concert.html#stage-now">ALL FOR YOU</a></td>
@@ -126,8 +126,8 @@
</a> </a>
</footer> </footer>
<script src="../particles.js"></script> <script src="../assets/js/particles.js"></script>
<script src="../portal-nav.js"></script> <script src="../assets/js/portal-nav.js"></script>
<script> <script>
(function () { (function () {
document.querySelectorAll('tr.archive-row-spotify[data-spotify-url]').forEach(function (row) { document.querySelectorAll('tr.archive-row-spotify[data-spotify-url]').forEach(function (row) {
File diff suppressed because it is too large. Load diff
+375 -375
View File
@@ -1,375 +1,375 @@
.story-timeline { .story-timeline {
position: relative; position: relative;
max-width: 1000px; max-width: 1000px;
margin: 50px auto; margin: 50px auto;
padding: 20px 0; padding: 20px 0;
} }
/* 中央貫穿軸線 */ /* 中央貫穿軸線 */
.story-timeline::after { .story-timeline::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 6px; width: 6px;
background-color: var(--primary); background-color: var(--primary);
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 50%; left: 50%;
margin-left: -3px; margin-left: -3px;
border-radius: 10px; border-radius: 10px;
} }
.timeline-box { .timeline-box {
padding: 10px 40px; padding: 10px 40px;
position: relative; position: relative;
width: 50%; width: 50%;
box-sizing: border-box; box-sizing: border-box;
} }
/* 圓形節點 */ /* 圓形節點 */
.timeline-box::after { .timeline-box::after {
content: '\f3a5'; content: '\f3a5';
font-family: "Font Awesome 6 Free" !important; font-family: "Font Awesome 6 Free" !important;
position: absolute; position: absolute;
width: 10px; width: 10px;
height: 10px; height: 10px;
right: -20px; right: -20px;
top: 15px; top: 15px;
z-index: 1; z-index: 1;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: #FFD700; color: #FFD700;
text-shadow: 0 0 8px rgba(255, 215, 0, 0.5); text-shadow: 0 0 8px rgba(255, 215, 0, 0.5);
} }
/* 左右交錯控制 */ /* 左右交錯控制 */
.left { .left {
left: 0; left: 0;
text-align: right; text-align: right;
} }
.right { .right {
left: 50%; left: 50%;
text-align: left; text-align: left;
} }
/* 日期標籤(膠囊型) */ /* 日期標籤(膠囊型) */
.date-tag { .date-tag {
display: inline-block; display: inline-block;
padding: 8px 20px; padding: 8px 20px;
background: var(--accent); background: var(--accent);
color: var(--text); color: var(--text);
border-radius: 50px; border-radius: 50px;
font-weight: bold; font-weight: bold;
margin-bottom: 10px; margin-bottom: 10px;
} }
.content h3 { .content h3 {
color: var(--primary); color: var(--primary);
margin: 10px 0; margin: 10px 0;
} }
.content p { .content p {
color: var(--text-muted); color: var(--text-muted);
line-height: 1.6; line-height: 1.6;
} }
#stage .stage-teaser { #stage .stage-teaser {
margin-bottom: 1.75rem; margin-bottom: 1.75rem;
padding-bottom: 1.25rem; padding-bottom: 1.25rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.08); border-bottom: 1px solid rgba(0, 0, 0, 0.08);
} }
#stage .stage-teaser:last-of-type { #stage .stage-teaser:last-of-type {
border-bottom: 0; border-bottom: 0;
margin-bottom: 0; margin-bottom: 0;
padding-bottom: 0; padding-bottom: 0;
} }
/* albums/albums.html:.archive-block 已改為 <section>,沿用 style.css 的 section 卡片版型 */ /* albums/albums.html:.archive-block 已改為 <section>,沿用 style.css 的 section 卡片版型 */
section.archive-block p { section.archive-block p {
color: #4a4a4a; color: #4a4a4a;
line-height: 1.7; line-height: 1.7;
margin: 0 0 0.75rem; margin: 0 0 0.75rem;
} }
section.archive-block p:last-child { section.archive-block p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
/* albums/albums.html:精選作品表(含封面欄) */ /* albums/albums.html:精選作品表(含封面欄) */
.archive-discography { .archive-discography {
width: 100%; width: 100%;
margin-top: 1.25rem; margin-top: 1.25rem;
} }
.archive-discography .album-cover-cell { .archive-discography .album-cover-cell {
width: 96px; width: 96px;
vertical-align: middle; vertical-align: middle;
text-align: center; text-align: center;
padding: 10px 8px; padding: 10px 8px;
} }
.archive-discography .album-cover-cell img { .archive-discography .album-cover-cell img {
width: 76px; width: 76px;
height: 76px; height: 76px;
object-fit: cover; object-fit: cover;
border-radius: 10px; border-radius: 10px;
border: 1px solid rgba(255, 204, 0, 0.28); border: 1px solid rgba(255, 204, 0, 0.28);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
display: block; display: block;
margin: 0 auto; margin: 0 auto;
background: #fff; background: #fff;
} }
.archive-discography tbody tr.archive-row-spotify { .archive-discography tbody tr.archive-row-spotify {
cursor: pointer; cursor: pointer;
} }
.archive-discography tbody tr.archive-row-spotify:hover td { .archive-discography tbody tr.archive-row-spotify:hover td {
background-color: rgba(255, 204, 0, 0.06); background-color: rgba(255, 204, 0, 0.06);
} }
.archive-discography tbody tr.archive-row-spotify:focus-visible { .archive-discography tbody tr.archive-row-spotify:focus-visible {
outline: 2px solid rgba(255, 204, 0, 0.65); outline: 2px solid rgba(255, 204, 0, 0.65);
outline-offset: -2px; outline-offset: -2px;
} }
.landing-intro { .landing-intro {
text-align: center; text-align: center;
padding: 28px 0 48px; padding: 28px 0 48px;
} }
.landing-actions .btn { .landing-actions .btn {
margin: 8px 6px; margin: 8px 6px;
} }
.archive-intro-lead { .archive-intro-lead {
text-align: center; text-align: center;
margin-top: 8px; margin-top: 8px;
} }
/* ---------- 首頁 home-page:閱讀寬度與字級(弱化對 vw 的依賴) ---------- */ /* ---------- 首頁 home-page:閱讀寬度與字級(弱化對 vw 的依賴) ---------- */
/* 用 px 鎖上限,避免 72rem 隨根字級/無障礙字級變大(例如實測出 ~1390px) */ /* 用 px 鎖上限,避免 72rem 隨根字級/無障礙字級變大(例如實測出 ~1390px) */
.home-page .container { .home-page .container {
max-width: min(1200px, calc(100% - 2rem)); max-width: min(1200px, calc(100% - 2rem));
width: 100%; width: 100%;
margin-inline: auto; margin-inline: auto;
padding: 2.5rem 1.25rem; padding: 2.5rem 1.25rem;
box-sizing: border-box; box-sizing: border-box;
} }
.home-page #start .intro-text, .home-page #start .intro-text,
.home-page .container>section .intro-text { .home-page .container>section .intro-text {
max-width: 42rem; max-width: 42rem;
margin-inline: auto; margin-inline: auto;
} }
.home-page #start .intro-text p.intro-text, .home-page #start .intro-text p.intro-text,
.home-page #start .core-description, .home-page #start .core-description,
.home-page #start .call-to-action, .home-page #start .call-to-action,
.home-page .container>section .intro-text>p.intro-text, .home-page .container>section .intro-text>p.intro-text,
.home-page .container>section .intro-text .core-description, .home-page .container>section .intro-text .core-description,
.home-page .container>section .intro-text .call-to-action { .home-page .container>section .intro-text .call-to-action {
font-size: 1.0625rem; font-size: 1.0625rem;
line-height: 1.75; line-height: 1.75;
color: #4a4a4a; color: #4a4a4a;
margin: 0 0 1.125rem; margin: 0 0 1.125rem;
} }
.home-page #start .intro-text p:last-child { .home-page #start .intro-text p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
/* 與首頁同欄寬:區塊內列表(minister_ge 等) */ /* 與首頁同欄寬:區塊內列表(minister_ge 等) */
.home-page .container>section .intro-text ul { .home-page .container>section .intro-text ul {
margin: 0.5rem 0 0; margin: 0.5rem 0 0;
padding-left: 1.2rem; padding-left: 1.2rem;
color: #4a4a4a; color: #4a4a4a;
line-height: 1.75; line-height: 1.75;
font-size: 1.0625rem; font-size: 1.0625rem;
} }
.home-page .container>section .intro-text ul li { .home-page .container>section .intro-text ul li {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.home-page .container>section .intro-text ul li:last-child { .home-page .container>section .intro-text ul li:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
/* 頂部一句話(深色底上,與舊 minister-hero-lead 同角色) */ /* 頂部一句話(深色底上,與舊 minister-hero-lead 同角色) */
.home-page .landing-intro { .home-page .landing-intro {
color: #ececec; color: #ececec;
max-width: 48rem; max-width: 48rem;
margin-inline: auto; margin-inline: auto;
} }
.home-page .landing-intro p { .home-page .landing-intro p {
font-size: 1.1rem; font-size: 1.1rem;
line-height: 1.65; line-height: 1.65;
margin: 0; margin: 0;
} }
.home-page .landing-intro .mark_b { .home-page .landing-intro .mark_b {
color: var(--light-yellow); color: var(--light-yellow);
} }
.home-page #intro .intro-text .slogan-quote--awakening + .core-description { .home-page #intro .intro-text .slogan-quote--awakening + .core-description {
margin-top: 1rem; margin-top: 1rem;
} }
/* 頁尾 CTA 區(首頁 landing-actions 延伸) */ /* 頁尾 CTA 區(首頁 landing-actions 延伸) */
.home-page .container>.landing-actions { .home-page .container>.landing-actions {
text-align: center; text-align: center;
margin-top: 0.5rem; margin-top: 0.5rem;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
/* minister_ge · 推廣部進化史:年份僅在軸標 data-era;卡內 h3 僅螢幕閱讀器可見 */ /* minister_ge · 推廣部進化史:年份僅在軸標 data-era;卡內 h3 僅螢幕閱讀器可見 */
.home-page #journey .journey-year-sr { .home-page #journey .journey-year-sr {
position: absolute; position: absolute;
width: 1px; width: 1px;
height: 1px; height: 1px;
padding: 0; padding: 0;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
white-space: nowrap; white-space: nowrap;
border: 0; border: 0;
} }
/* 推廣部進化史:副標白票。2016 僅用你提供的三個數值;年分黃票不改(沿用 style.css 的 ::after) */ /* 推廣部進化史:副標白票。2016 僅用你提供的三個數值;年分黃票不改(沿用 style.css 的 ::after) */
.home-page #journey .merged-storyline .story-node:has(.journey-sublabel) { .home-page #journey .merged-storyline .story-node:has(.journey-sublabel) {
padding-top: 42px; padding-top: 42px;
} }
/* 疊序(僅此區):軸點鑽石 < 副標白票 < 年分黃標(標題在上) */ /* 疊序(僅此區):軸點鑽石 < 副標白票 < 年分黃標(標題在上) */
.home-page #journey .merged-storyline .story-node::before { .home-page #journey .merged-storyline .story-node::before {
z-index: 2; z-index: 2;
} }
.home-page #journey .merged-storyline .story-node::after { .home-page #journey .merged-storyline .story-node::after {
z-index: 6; z-index: 6;
} }
.home-page #journey .merged-storyline .story-node .journey-sublabel { .home-page #journey .merged-storyline .story-node .journey-sublabel {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
margin: 0; margin: 0;
padding: 4px 10px; padding: 4px 10px;
border-radius: 8px; border-radius: 8px;
font-size: 0.68rem; font-size: 0.68rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 1.25; line-height: 1.25;
color: #2a2a2a; color: #2a2a2a;
text-align: center; text-align: center;
background: linear-gradient(180deg, #fffef6 0%, #fff3d6 100%); background: linear-gradient(180deg, #fffef6 0%, #fff3d6 100%);
border: 2px solid #fff; border: 2px solid #fff;
box-shadow: 1px 3px 7px rgba(0, 0, 0, 0.12); box-shadow: 1px 3px 7px rgba(0, 0, 0, 0.12);
max-width: 8rem; max-width: 8rem;
box-sizing: border-box; box-sizing: border-box;
} }
/* 2016 基準(奇,靠軸角在右上):你給的 right / top / 角 */ /* 2016 基準(奇,靠軸角在右上):你給的 right / top / 角 */
.home-page #journey .merged-storyline .story-node:nth-of-type(odd):has(.journey-sublabel) .journey-sublabel { .home-page #journey .merged-storyline .story-node:nth-of-type(odd):has(.journey-sublabel) .journey-sublabel {
right: 45px; right: 45px;
top: -8px; top: -8px;
transform: rotate(-10deg); transform: rotate(-10deg);
transform-origin: center center; transform-origin: center center;
} }
/* 2017 鏡像(偶,靠軸角在左上):角度 +10°;left 依實機微調 */ /* 2017 鏡像(偶,靠軸角在左上):角度 +10°;left 依實機微調 */
.home-page #journey .merged-storyline .story-node:nth-of-type(even):has(.journey-sublabel) .journey-sublabel { .home-page #journey .merged-storyline .story-node:nth-of-type(even):has(.journey-sublabel) .journey-sublabel {
left: 40px; left: 40px;
top: 2px; top: 2px;
transform: rotate(10deg); transform: rotate(10deg);
transform-origin: center center; transform-origin: center center;
} }
.home-page #journey .merged-storyline .story-node .journey-sublabel + .journey-month { .home-page #journey .merged-storyline .story-node .journey-sublabel + .journey-month {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.home-page #journey .merged-storyline .story-node .journey-month { .home-page #journey .merged-storyline .story-node .journey-month {
margin: 0.75rem 0 0.3rem; margin: 0.75rem 0 0.3rem;
padding: 0.32rem 0.7rem 0.32rem 0; padding: 0.32rem 0.7rem 0.32rem 0;
border-right: 3px solid var(--primary); border-right: 3px solid var(--primary);
border-left: 0; border-left: 0;
font-size: 0.82rem; font-size: 0.82rem;
font-weight: 800; font-weight: 800;
letter-spacing: 0.1em; letter-spacing: 0.1em;
color: #6b5210; color: #6b5210;
line-height: 1.35; line-height: 1.35;
background: linear-gradient(270deg, rgba(255, 204, 0, 0.14) 0%, transparent 100%); background: linear-gradient(270deg, rgba(255, 204, 0, 0.14) 0%, transparent 100%);
} }
.home-page #journey .merged-storyline .story-node .journey-month + p { .home-page #journey .merged-storyline .story-node .journey-month + p {
margin-top: 0; margin-top: 0;
margin-bottom: 0.35rem; margin-bottom: 0.35rem;
} }
.home-page #journey .merged-storyline .story-node .journey-milestone { .home-page #journey .merged-storyline .story-node .journey-milestone {
margin: 1rem 0 0.35rem; margin: 1rem 0 0.35rem;
padding-top: 0.5rem; padding-top: 0.5rem;
border-top: 1px dashed rgba(255, 204, 0, 0.45); border-top: 1px dashed rgba(255, 204, 0, 0.45);
font-size: 0.78rem; font-size: 0.78rem;
font-weight: 800; font-weight: 800;
letter-spacing: 0.14em; letter-spacing: 0.14em;
color: #8a6910; color: #8a6910;
} }
.home-page #journey .merged-storyline .story-node .journey-milestone + p { .home-page #journey .merged-storyline .story-node .journey-milestone + p {
margin-top: 0; margin-top: 0;
} }
.home-page #story > p.intro-text { .home-page #story > p.intro-text {
max-width: 44rem; max-width: 44rem;
margin-inline: auto; margin-inline: auto;
margin-bottom: 1.25rem; margin-bottom: 1.25rem;
font-size: 1.0625rem; font-size: 1.0625rem;
line-height: 1.75; line-height: 1.75;
color: #4a4a4a; color: #4a4a4a;
} }
@media (max-width: 900px) { @media (max-width: 900px) {
/* 主軸在左:僅微調副標橫向;年分仍用全站 merged-storyline 規則 */ /* 主軸在左:僅微調副標橫向;年分仍用全站 merged-storyline 規則 */
.home-page #journey .merged-storyline .story-node:nth-of-type(odd):has(.journey-sublabel) .journey-sublabel { .home-page #journey .merged-storyline .story-node:nth-of-type(odd):has(.journey-sublabel) .journey-sublabel {
left: 48px; left: 48px;
right: auto; right: auto;
top: -8px; top: -8px;
transform: rotate(-10deg); transform: rotate(-10deg);
} }
.home-page #journey .merged-storyline .story-node:nth-of-type(even):has(.journey-sublabel) .journey-sublabel { .home-page #journey .merged-storyline .story-node:nth-of-type(even):has(.journey-sublabel) .journey-sublabel {
left: 58px; left: 58px;
right: auto; right: auto;
top: 2px; top: 2px;
transform: rotate(10deg); transform: rotate(10deg);
} }
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.home-page .container { .home-page .container {
padding: 1.75rem 1rem; padding: 1.75rem 1rem;
} }
.home-page #start .intro-text p.intro-text, .home-page #start .intro-text p.intro-text,
.home-page #start .core-description, .home-page #start .core-description,
.home-page #start .call-to-action, .home-page #start .call-to-action,
.home-page .container>section .intro-text>p.intro-text, .home-page .container>section .intro-text>p.intro-text,
.home-page .container>section .intro-text .core-description, .home-page .container>section .intro-text .core-description,
.home-page .container>section .intro-text .call-to-action, .home-page .container>section .intro-text .call-to-action,
.home-page .container>section .intro-text ul, .home-page .container>section .intro-text ul,
.home-page #story > p.intro-text { .home-page #story > p.intro-text {
font-size: 1rem; font-size: 1rem;
} }
} }
File renamed without changes.
+2 -2
View File
@@ -48,7 +48,7 @@ header {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
min-height: 100dvh; min-height: 100dvh;
background-image: url('images/header.jpg'); background-image: url('../images/header.jpg');
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 108%; background-size: 108%;
@@ -1084,7 +1084,7 @@ footer a .mark_b {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
min-height: 100dvh; min-height: 100dvh;
background-image: url('images/header.jpg'); background-image: url('../images/header.jpg');
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 108%; background-size: 108%;
+218 -218
View File
@@ -1,218 +1,218 @@
/* iPad/平板 RWD — max-width ≤1180px(含 iPad 直/橫與小平板/小筆電) */ /* iPad/平板 RWD — max-width ≤1180px(含 iPad 直/橫與小平板/小筆電) */
@media (max-width: 1180px) { @media (max-width: 1180px) {
html:has(body.map-page) { html:has(body.map-page) {
scroll-padding-top: clamp(52px, 12vw, 76px); scroll-padding-top: clamp(52px, 12vw, 76px);
} }
nav, nav,
.portal-nav { .portal-nav {
padding-left: clamp(14px, 2vw + 10px, 32px) !important; padding-left: clamp(14px, 2vw + 10px, 32px) !important;
padding-right: clamp(14px, 2vw + 10px, 32px) !important; padding-right: clamp(14px, 2vw + 10px, 32px) !important;
row-gap: 12px; row-gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-start; align-items: flex-start;
} }
.map-page .portal-nav { .map-page .portal-nav {
padding-left: clamp(14px, 2vw + 10px, 32px) !important; padding-left: clamp(14px, 2vw + 10px, 32px) !important;
padding-right: clamp(14px, 2vw + 10px, 32px) !important; padding-right: clamp(14px, 2vw + 10px, 32px) !important;
} }
.portal-nav .logo { .portal-nav .logo {
width: min(240px, 38vw); width: min(240px, 38vw);
max-width: 100%; max-width: 100%;
flex-shrink: 0; flex-shrink: 0;
} }
.portal-nav>ul { .portal-nav>ul {
flex-wrap: wrap; flex-wrap: wrap;
gap: clamp(12px, 2vw, 18px); gap: clamp(12px, 2vw, 18px);
justify-content: flex-end; justify-content: flex-end;
min-width: 0; min-width: 0;
flex: 1 1 280px; flex: 1 1 280px;
} }
.portal-nav>ul>li>a { .portal-nav>ul>li>a {
min-height: 44px; min-height: 44px;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
nav ul { nav ul {
gap: clamp(12px, 2vw, 20px); gap: clamp(12px, 2vw, 20px);
} }
header { header {
background-size: cover; background-size: cover;
background-position: center center; background-position: center center;
} }
.hero h1 { .hero h1 {
font-size: clamp(1.75rem, 2.25vw + 1rem, 2.35rem); font-size: clamp(1.75rem, 2.25vw + 1rem, 2.35rem);
} }
.hero p { .hero p {
font-size: clamp(1rem, 1.5vw + 0.65rem, 1.15rem); font-size: clamp(1rem, 1.5vw + 0.65rem, 1.15rem);
} }
.container, .container,
.content-container { .content-container {
padding-left: clamp(14px, 1.5vw + 10px, 22px); padding-left: clamp(14px, 1.5vw + 10px, 22px);
padding-right: clamp(14px, 1.5vw + 10px, 22px); padding-right: clamp(14px, 1.5vw + 10px, 22px);
} }
.home-page .container { .home-page .container {
padding-left: clamp(14px, 1.5vw + 10px, 22px); padding-left: clamp(14px, 1.5vw + 10px, 22px);
padding-right: clamp(14px, 1.5vw + 10px, 22px); padding-right: clamp(14px, 1.5vw + 10px, 22px);
} }
section { section {
padding: clamp(26px, 3vw + 18px, 36px) clamp(16px, 2.5vw + 12px, 28px) !important; padding: clamp(26px, 3vw + 18px, 36px) clamp(16px, 2.5vw + 12px, 28px) !important;
} }
.story-grid { .story-grid {
gap: clamp(18px, 4vw, 28px); gap: clamp(18px, 4vw, 28px);
grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
} }
.card { .card {
padding: clamp(18px, 4vw, 26px); padding: clamp(18px, 4vw, 26px);
} }
table { table {
font-size: 0.92rem; font-size: 0.92rem;
} }
table th, table th,
table td { table td {
padding: clamp(10px, 2vw, 14px); padding: clamp(10px, 2vw, 14px);
} }
/* 首頁/跨時空軌跡:鑽石主軸在平板改左側縱線(對齊舊 ≤900px 邏輯) */ /* 首頁/跨時空軌跡:鑽石主軸在平板改左側縱線(對齊舊 ≤900px 邏輯) */
.merged-storyline::before { .merged-storyline::before {
left: 18px; left: 18px;
transform: none; transform: none;
} }
.merged-storyline .story-node { .merged-storyline .story-node {
width: calc(100% - 44px); width: calc(100% - 44px);
margin-left: 44px; margin-left: 44px;
margin-right: 0; margin-right: 0;
} }
.merged-storyline .story-node:nth-of-type(odd), .merged-storyline .story-node:nth-of-type(odd),
.merged-storyline .story-node:nth-of-type(even) { .merged-storyline .story-node:nth-of-type(even) {
margin-left: 44px; margin-left: 44px;
margin-right: 0; margin-right: 0;
} }
.merged-storyline .story-node::before { .merged-storyline .story-node::before {
left: -39px; left: -39px;
right: auto; right: auto;
} }
.merged-storyline .story-node::after { .merged-storyline .story-node::after {
left: 14px; left: 14px;
right: auto; right: auto;
transform: rotate(-8deg); transform: rotate(-8deg);
} }
/* 紀實長卷/pillar 段落 */ /* 紀實長卷/pillar 段落 */
.chronicle-reader, .chronicle-reader,
.chronicle-pager { .chronicle-pager {
max-width: min(920px, 100%); max-width: min(920px, 100%);
} }
.variety-block { .variety-block {
padding: clamp(18px, 4vw, 22px); padding: clamp(18px, 4vw, 22px);
} }
.map-archive-header .main-title, .map-archive-header .main-title,
.concert-archive-header .main-title { .concert-archive-header .main-title {
letter-spacing: clamp(3px, 1vw, 6px); letter-spacing: clamp(3px, 1vw, 6px);
} }
.map-layout { .map-layout {
grid-template-columns: minmax(280px, 42%) minmax(0, 1fr); grid-template-columns: minmax(280px, 42%) minmax(0, 1fr);
gap: clamp(16px, 3vw, 22px); gap: clamp(16px, 3vw, 22px);
} }
.map-my-maps-frame { .map-my-maps-frame {
height: min(52vh, 520px); height: min(52vh, 520px);
min-height: 360px; min-height: 360px;
} }
.map-embed-all { .map-embed-all {
gap: 12px; gap: 12px;
} }
/* 重逢區兩張演唱會大卡之間留白 */ /* 重逢區兩張演唱會大卡之間留白 */
#stage-now { #stage-now {
gap: clamp(36px, 5vw, 50px); gap: clamp(36px, 5vw, 50px);
} }
/* 演唱會卡片內距 */ /* 演唱會卡片內距 */
.con-1, .con-1,
.con-2, .con-2,
.con-3, .con-3,
.con-4, .con-4,
#yellownote-stage { #yellownote-stage {
padding: clamp(32px, 5vw, 44px) clamp(22px, 5vw, 48px) !important; padding: clamp(32px, 5vw, 44px) clamp(22px, 5vw, 48px) !important;
} }
.title { .title {
margin: clamp(24px, 5vw, 40px) !important; margin: clamp(24px, 5vw, 40px) !important;
font-size: clamp(1.15rem, 2.8vw, 1.45rem); font-size: clamp(1.15rem, 2.8vw, 1.45rem);
} }
.concert-container { .concert-container {
padding-left: clamp(12px, 3vw, 20px); padding-left: clamp(12px, 3vw, 20px);
padding-right: clamp(12px, 3vw, 20px); padding-right: clamp(12px, 3vw, 20px);
} }
.search-input:focus { .search-input:focus {
max-width: 100%; max-width: 100%;
} }
.concert-page .search-input:focus { .concert-page .search-input:focus {
width: min(100%, 440px); width: min(100%, 440px);
} }
.concert-page img[src*="images/concert/"] { .concert-page img[src*="assets/images/concert/"] {
width: min(560px, 88%); width: min(560px, 88%);
max-width: 100%; max-width: 100%;
} }
/* 歌詞頁 */ /* 歌詞頁 */
body.lyrics-page { body.lyrics-page {
margin: clamp(24px, 5vw, 56px) !important; margin: clamp(24px, 5vw, 56px) !important;
box-sizing: border-box; box-sizing: border-box;
overflow-x: hidden; overflow-x: hidden;
} }
html:has(body.lyrics-page) { html:has(body.lyrics-page) {
font-size: 118.75% !important; font-size: 118.75% !important;
} }
body.lyrics-page .lyrics-main-table { body.lyrics-page .lyrics-main-table {
border-spacing: clamp(12px, 3vw, 24px) !important; border-spacing: clamp(12px, 3vw, 24px) !important;
max-width: 100%; max-width: 100%;
} }
body.lyrics-page .main-left { body.lyrics-page .main-left {
width: 100% !important; width: 100% !important;
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
} }
body.lyrics-page .lyrics-main-table p { body.lyrics-page .lyrics-main-table p {
font-size: 1.2rem !important; font-size: 1.2rem !important;
max-width: none; max-width: none;
} }
body.lyrics-page h1 { body.lyrics-page h1 {
font-size: clamp(1.6rem, 5vw, 2.1rem) !important; font-size: clamp(1.6rem, 5vw, 2.1rem) !important;
} }
} }
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+304 -304
View File
@@ -1,304 +1,304 @@
(() => { (() => {
const canvas = document.getElementById("particles"); const canvas = document.getElementById("particles");
if (canvas) { if (canvas) {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
let particles = []; let particles = [];
function resizeCanvas() { function resizeCanvas() {
canvas.width = window.innerWidth; canvas.width = window.innerWidth;
canvas.height = window.innerHeight; canvas.height = window.innerHeight;
} }
class Particle { class Particle {
constructor() { constructor() {
this.x = Math.random() * canvas.width; this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height; this.y = Math.random() * canvas.height;
this.size = Math.random() * 4 + 1; this.size = Math.random() * 4 + 1;
this.speedX = Math.random() * 0.5 - 0.25; this.speedX = Math.random() * 0.5 - 0.25;
this.speedY = Math.random() * 0.5 + 0.2; this.speedY = Math.random() * 0.5 + 0.2;
} }
update() { update() {
this.x += this.speedX; this.x += this.speedX;
this.y += this.speedY; this.y += this.speedY;
if (this.y > canvas.height) this.y = 0; if (this.y > canvas.height) this.y = 0;
} }
draw() { draw() {
ctx.fillStyle = "#FFDD00"; ctx.fillStyle = "#FFDD00";
ctx.globalAlpha = 0.6; ctx.globalAlpha = 0.6;
ctx.beginPath(); ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill(); ctx.fill();
} }
} }
function initParticles() { function initParticles() {
particles = []; particles = [];
for (let i = 0; i < 80; i += 1) { for (let i = 0; i < 80; i += 1) {
particles.push(new Particle()); particles.push(new Particle());
} }
} }
function animateParticles() { function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const particle of particles) { for (const particle of particles) {
particle.update(); particle.update();
particle.draw(); particle.draw();
} }
requestAnimationFrame(animateParticles); requestAnimationFrame(animateParticles);
} }
resizeCanvas(); resizeCanvas();
initParticles(); initParticles();
animateParticles(); animateParticles();
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
resizeCanvas(); resizeCanvas();
initParticles(); initParticles();
}); });
} }
const tabs = Array.from(document.querySelectorAll(".tab-btn")); const tabs = Array.from(document.querySelectorAll(".tab-btn"));
const cards = Array.from(document.querySelectorAll(".polaroid-card")); const cards = Array.from(document.querySelectorAll(".polaroid-card"));
const searchInput = document.getElementById("itinerary-search"); const searchInput = document.getElementById("itinerary-search");
const itineraryList = document.querySelector(".itinerary-list"); const itineraryList = document.querySelector(".itinerary-list");
const detailPanel = document.getElementById("detail-panel"); const detailPanel = document.getElementById("detail-panel");
const detailDate = document.getElementById("detail-date"); const detailDate = document.getElementById("detail-date");
const detailTitle = document.getElementById("detail-title"); const detailTitle = document.getElementById("detail-title");
const detailDesc = document.getElementById("detail-desc"); const detailDesc = document.getElementById("detail-desc");
const detailQuote = document.getElementById("detail-quote"); const detailQuote = document.getElementById("detail-quote");
const detailTag = document.getElementById("detail-tag"); const detailTag = document.getElementById("detail-tag");
const detailLink = document.getElementById("detail-link"); const detailLink = document.getElementById("detail-link");
const detailImage = document.getElementById("detail-image"); const detailImage = document.getElementById("detail-image");
const memberMapFrame = document.getElementById("member-map"); const memberMapFrame = document.getElementById("member-map");
const mapEmbedSingle = document.getElementById("map-embed-single"); const mapEmbedSingle = document.getElementById("map-embed-single");
const mapEmbedAll = document.getElementById("map-embed-all"); const mapEmbedAll = document.getElementById("map-embed-all");
const openMapLink = document.getElementById("open-map-link"); const openMapLink = document.getElementById("open-map-link");
const openMapLinksDual = document.getElementById("open-map-links-dual"); const openMapLinksDual = document.getElementById("open-map-links-dual");
const openMapLinkKo = document.getElementById("open-map-link-ko"); const openMapLinkKo = document.getElementById("open-map-link-ko");
const openMapLinkEun = document.getElementById("open-map-link-eun"); const openMapLinkEun = document.getElementById("open-map-link-eun");
const dayGroups = new Map(); const dayGroups = new Map();
let currentMember = "all"; let currentMember = "all";
let currentKeyword = ""; let currentKeyword = "";
const memberMaps = { const memberMaps = {
eun: { eun: {
embed: "https://www.google.com/maps/d/embed?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI&ehbc=2E312F", 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" open: "https://www.google.com/maps/d/u/0/viewer?mid=1VGZ76SPPjm3NWCBQe-hkm08oe5WPRJI"
}, },
ko: { ko: {
embed: "https://www.google.com/maps/d/embed?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw&hl=zh-TW&ehbc=2E312F", 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" open: "https://www.google.com/maps/d/u/0/viewer?mid=1xpAsSoO8gNmMiW4x2sfkndISFTtjMQDw"
} }
}; };
const memberTripPrefix = { const memberTripPrefix = {
ko: "高高父子遊台灣", ko: "高高父子遊台灣",
eun: "殷空少搭飛機去台灣高雄" eun: "殷空少搭飛機去台灣高雄"
}; };
const memberSortOrder = { ko: 0, eun: 1 }; const memberSortOrder = { ko: 0, eun: 1 };
function normalizeMember(member) { function normalizeMember(member) {
if (member === "kogo") return "ko"; if (member === "kogo") return "ko";
return member; return member;
} }
function getMemberLabel(member) { function getMemberLabel(member) {
const normalized = normalizeMember(member); const normalized = normalizeMember(member);
if (normalized === "eun") return "殷志源"; if (normalized === "eun") return "殷志源";
if (normalized === "ko") return "高志溶"; if (normalized === "ko") return "高志溶";
return "未分類"; return "未分類";
} }
function getDayToken(rawDate) { function getDayToken(rawDate) {
const match = String(rawDate || "").match(/Day\s*(\d+)/i); const match = String(rawDate || "").match(/Day\s*(\d+)/i);
if (!match) return String(rawDate || "未分類"); if (!match) return String(rawDate || "未分類");
return "Day " + match[1]; return "Day " + match[1];
} }
function getGroupLabel(card) { function getGroupLabel(card) {
const date = getDayToken(card.dataset.date || "未分類"); const date = getDayToken(card.dataset.date || "未分類");
const normalized = normalizeMember(card.dataset.member || ""); const normalized = normalizeMember(card.dataset.member || "");
const prefix = memberTripPrefix[normalized] || getMemberLabel(normalized); const prefix = memberTripPrefix[normalized] || getMemberLabel(normalized);
return prefix + "_" + date; return prefix + "_" + date;
} }
function setDualMapVisible(isAll) { function setDualMapVisible(isAll) {
if (mapEmbedSingle && mapEmbedAll) { if (mapEmbedSingle && mapEmbedAll) {
mapEmbedSingle.hidden = isAll ? true : false; mapEmbedSingle.hidden = isAll ? true : false;
mapEmbedAll.hidden = isAll ? false : true; mapEmbedAll.hidden = isAll ? false : true;
mapEmbedAll.setAttribute("aria-hidden", isAll ? "false" : "true"); mapEmbedAll.setAttribute("aria-hidden", isAll ? "false" : "true");
} }
if (openMapLink && openMapLinksDual) { if (openMapLink && openMapLinksDual) {
openMapLink.hidden = isAll ? true : false; openMapLink.hidden = isAll ? true : false;
openMapLinksDual.hidden = isAll ? false : true; openMapLinksDual.hidden = isAll ? false : true;
} }
} }
function updateMapByMember(member) { function updateMapByMember(member) {
const normalized = normalizeMember(member); const normalized = normalizeMember(member);
if (normalized === "all") { if (normalized === "all") {
setDualMapVisible(true); setDualMapVisible(true);
if (openMapLinkKo) openMapLinkKo.href = memberMaps.ko.open; if (openMapLinkKo) openMapLinkKo.href = memberMaps.ko.open;
if (openMapLinkEun) openMapLinkEun.href = memberMaps.eun.open; if (openMapLinkEun) openMapLinkEun.href = memberMaps.eun.open;
return; return;
} }
setDualMapVisible(false); setDualMapVisible(false);
const mapConfig = memberMaps[normalized]; const mapConfig = memberMaps[normalized];
if (!mapConfig || !memberMapFrame) return; if (!mapConfig || !memberMapFrame) return;
memberMapFrame.src = mapConfig.embed; memberMapFrame.src = mapConfig.embed;
if (openMapLink) openMapLink.href = mapConfig.open; if (openMapLink) openMapLink.href = mapConfig.open;
} }
function getCardSearchText(card) { function getCardSearchText(card) {
return [ return [
card.dataset.date || "", card.dataset.date || "",
card.dataset.title || "", card.dataset.title || "",
card.dataset.desc || "", card.dataset.desc || "",
card.dataset.tag || "", card.dataset.tag || "",
].join(" ").toLowerCase(); ].join(" ").toLowerCase();
} }
function createDayGroup(dayLabel) { function createDayGroup(dayLabel) {
const group = document.createElement("section"); const group = document.createElement("section");
group.className = "day-group"; group.className = "day-group";
group.dataset.day = dayLabel; group.dataset.day = dayLabel;
const toggle = document.createElement("button"); const toggle = document.createElement("button");
toggle.type = "button"; toggle.type = "button";
toggle.className = "day-toggle"; toggle.className = "day-toggle";
toggle.setAttribute("aria-expanded", "false"); toggle.setAttribute("aria-expanded", "false");
toggle.innerHTML = "<span>" + dayLabel + "</span><i class='fa-solid fa-chevron-down'></i>"; toggle.innerHTML = "<span>" + dayLabel + "</span><i class='fa-solid fa-chevron-down'></i>";
const body = document.createElement("div"); const body = document.createElement("div");
body.className = "day-cards"; body.className = "day-cards";
body.style.display = "none"; body.style.display = "none";
group.appendChild(toggle); group.appendChild(toggle);
group.appendChild(body); group.appendChild(body);
itineraryList.insertBefore(group, detailPanel); itineraryList.insertBefore(group, detailPanel);
dayGroups.set(dayLabel, { group, toggle, body }); dayGroups.set(dayLabel, { group, toggle, body });
return dayGroups.get(dayLabel); return dayGroups.get(dayLabel);
} }
function setDayExpanded(dayGroup, shouldExpand) { function setDayExpanded(dayGroup, shouldExpand) {
dayGroup.toggle.setAttribute("aria-expanded", shouldExpand ? "true" : "false"); dayGroup.toggle.setAttribute("aria-expanded", shouldExpand ? "true" : "false");
dayGroup.body.style.display = shouldExpand ? "grid" : "none"; dayGroup.body.style.display = shouldExpand ? "grid" : "none";
dayGroup.group.classList.toggle("expanded", shouldExpand); dayGroup.group.classList.toggle("expanded", shouldExpand);
} }
function initializeDayGroups() { function initializeDayGroups() {
const sortedCards = [...cards].sort((a, b) => { const sortedCards = [...cards].sort((a, b) => {
const memberA = normalizeMember(a.dataset.member || ""); const memberA = normalizeMember(a.dataset.member || "");
const memberB = normalizeMember(b.dataset.member || ""); const memberB = normalizeMember(b.dataset.member || "");
const memberDiff = (memberSortOrder[memberA] ?? 99) - (memberSortOrder[memberB] ?? 99); const memberDiff = (memberSortOrder[memberA] ?? 99) - (memberSortOrder[memberB] ?? 99);
if (memberDiff !== 0) return memberDiff; if (memberDiff !== 0) return memberDiff;
const dayA = Number((getDayToken(a.dataset.date).match(/\d+/) || [999])[0]); const dayA = Number((getDayToken(a.dataset.date).match(/\d+/) || [999])[0]);
const dayB = Number((getDayToken(b.dataset.date).match(/\d+/) || [999])[0]); const dayB = Number((getDayToken(b.dataset.date).match(/\d+/) || [999])[0]);
return dayA - dayB; return dayA - dayB;
}); });
sortedCards.forEach((card) => { sortedCards.forEach((card) => {
const dayLabel = getGroupLabel(card); const dayLabel = getGroupLabel(card);
const dayGroup = dayGroups.get(dayLabel) || createDayGroup(dayLabel); const dayGroup = dayGroups.get(dayLabel) || createDayGroup(dayLabel);
dayGroup.body.appendChild(card); dayGroup.body.appendChild(card);
}); });
} }
function updateDayGroupVisibility() { function updateDayGroupVisibility() {
dayGroups.forEach(({ group, body, toggle }) => { dayGroups.forEach(({ group, body, toggle }) => {
const visibleCards = Array.from(body.querySelectorAll(".polaroid-card")).filter((card) => card.style.display !== "none"); const visibleCards = Array.from(body.querySelectorAll(".polaroid-card")).filter((card) => card.style.display !== "none");
group.style.display = visibleCards.length ? "" : "none"; group.style.display = visibleCards.length ? "" : "none";
if (!visibleCards.length) { if (!visibleCards.length) {
setDayExpanded({ group, toggle, body }, false); setDayExpanded({ group, toggle, body }, false);
} }
}); });
} }
function ensureExpandedForCard(card) { function ensureExpandedForCard(card) {
const dayGroup = dayGroups.get(getGroupLabel(card)); const dayGroup = dayGroups.get(getGroupLabel(card));
if (!dayGroup) return; if (!dayGroup) return;
setDayExpanded(dayGroup, true); setDayExpanded(dayGroup, true);
} }
function setActiveCard(card, options = {}) { function setActiveCard(card, options = {}) {
const { expandDay = true } = options; const { expandDay = true } = options;
cards.forEach((item) => item.classList.remove("active")); cards.forEach((item) => item.classList.remove("active"));
card.classList.add("active"); card.classList.add("active");
if (expandDay) { if (expandDay) {
ensureExpandedForCard(card); ensureExpandedForCard(card);
} }
const mapKey = currentMember === "all" ? "all" : currentMember; const mapKey = currentMember === "all" ? "all" : currentMember;
updateMapByMember(mapKey); updateMapByMember(mapKey);
detailDate.textContent = card.dataset.date || ""; detailDate.textContent = card.dataset.date || "";
detailTitle.textContent = card.dataset.title || ""; detailTitle.textContent = card.dataset.title || "";
detailDesc.textContent = card.dataset.desc || ""; detailDesc.textContent = card.dataset.desc || "";
detailQuote.textContent = "「" + (card.dataset.quote || "") + "」"; detailQuote.textContent = "「" + (card.dataset.quote || "") + "」";
detailTag.textContent = card.dataset.tag || ""; detailTag.textContent = card.dataset.tag || "";
detailLink.href = card.dataset.link || "#"; detailLink.href = card.dataset.link || "#";
detailImage.src = card.querySelector("img").src; detailImage.src = card.querySelector("img").src;
detailImage.alt = "節目截圖 - " + (card.dataset.title || "行程地點"); detailImage.alt = "節目截圖 - " + (card.dataset.title || "行程地點");
} }
function applyFilter() { function applyFilter() {
let firstVisible = null; let firstVisible = null;
cards.forEach((card) => { cards.forEach((card) => {
const cardMember = normalizeMember(card.dataset.member || ""); const cardMember = normalizeMember(card.dataset.member || "");
const matchedMember = currentMember === "all" || cardMember === currentMember; const matchedMember = currentMember === "all" || cardMember === currentMember;
const matchedKeyword = !currentKeyword || getCardSearchText(card).includes(currentKeyword); const matchedKeyword = !currentKeyword || getCardSearchText(card).includes(currentKeyword);
const matched = matchedMember && matchedKeyword; const matched = matchedMember && matchedKeyword;
card.style.display = matched ? "" : "none"; card.style.display = matched ? "" : "none";
if (matched && !firstVisible) firstVisible = card; if (matched && !firstVisible) firstVisible = card;
}); });
updateDayGroupVisibility(); updateDayGroupVisibility();
const activeVisibleCard = cards.find((card) => card.classList.contains("active") && card.style.display !== "none"); const activeVisibleCard = cards.find((card) => card.classList.contains("active") && card.style.display !== "none");
const fallbackCard = activeVisibleCard || firstVisible; const fallbackCard = activeVisibleCard || firstVisible;
if (fallbackCard) { if (fallbackCard) {
setActiveCard(fallbackCard, { expandDay: false }); setActiveCard(fallbackCard, { expandDay: false });
} else { } else {
updateMapByMember(currentMember === "all" ? "all" : currentMember); updateMapByMember(currentMember === "all" ? "all" : currentMember);
} }
} }
tabs.forEach((tab) => { tabs.forEach((tab) => {
tab.addEventListener("click", () => { tab.addEventListener("click", () => {
tabs.forEach((item) => { tabs.forEach((item) => {
item.classList.remove("active"); item.classList.remove("active");
item.setAttribute("aria-pressed", "false"); item.setAttribute("aria-pressed", "false");
}); });
tab.classList.add("active"); tab.classList.add("active");
tab.setAttribute("aria-pressed", "true"); tab.setAttribute("aria-pressed", "true");
currentMember = normalizeMember(tab.dataset.member || "all"); currentMember = normalizeMember(tab.dataset.member || "all");
applyFilter(); applyFilter();
}); });
}); });
if (searchInput) { if (searchInput) {
searchInput.addEventListener("input", (event) => { searchInput.addEventListener("input", (event) => {
currentKeyword = event.target.value.trim().toLowerCase(); currentKeyword = event.target.value.trim().toLowerCase();
applyFilter(); applyFilter();
}); });
} }
itineraryList.addEventListener("click", (event) => { itineraryList.addEventListener("click", (event) => {
const toggle = event.target.closest(".day-toggle"); const toggle = event.target.closest(".day-toggle");
if (!toggle) return; if (!toggle) return;
const group = toggle.closest(".day-group"); const group = toggle.closest(".day-group");
if (!group) return; if (!group) return;
const dayGroup = dayGroups.get(group.dataset.day); const dayGroup = dayGroups.get(group.dataset.day);
if (!dayGroup) return; if (!dayGroup) return;
const isExpanded = dayGroup.toggle.getAttribute("aria-expanded") === "true"; const isExpanded = dayGroup.toggle.getAttribute("aria-expanded") === "true";
setDayExpanded(dayGroup, !isExpanded); setDayExpanded(dayGroup, !isExpanded);
}); });
cards.forEach((card) => { cards.forEach((card) => {
card.addEventListener("click", () => { card.addEventListener("click", () => {
setActiveCard(card, { expandDay: true }); setActiveCard(card, { expandDay: true });
if (window.innerWidth < 920) { if (window.innerWidth < 920) {
detailPanel.scrollIntoView({ behavior: "smooth", block: "start" }); detailPanel.scrollIntoView({ behavior: "smooth", block: "start" });
} }
}); });
}); });
initializeDayGroups(); initializeDayGroups();
applyFilter(); applyFilter();
})(); })();
+58 -58
View File
@@ -1,58 +1,58 @@
(() => { (() => {
const canvas = document.getElementById("particles"); const canvas = document.getElementById("particles");
if (!canvas) return; if (!canvas) return;
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
let particles = []; let particles = [];
function resizeCanvas() { function resizeCanvas() {
canvas.width = window.innerWidth; canvas.width = window.innerWidth;
canvas.height = window.innerHeight; canvas.height = window.innerHeight;
} }
class Particle { class Particle {
constructor() { constructor() {
this.x = Math.random() * canvas.width; this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height; this.y = Math.random() * canvas.height;
this.size = Math.random() * 4 + 1; this.size = Math.random() * 4 + 1;
this.speedX = Math.random() * 0.5 - 0.25; this.speedX = Math.random() * 0.5 - 0.25;
this.speedY = Math.random() * 0.5 + 0.2; this.speedY = Math.random() * 0.5 + 0.2;
} }
update() { update() {
this.x += this.speedX; this.x += this.speedX;
this.y += this.speedY; this.y += this.speedY;
if (this.y > canvas.height) this.y = 0; if (this.y > canvas.height) this.y = 0;
} }
draw() { draw() {
ctx.fillStyle = "#FFDD00"; ctx.fillStyle = "#FFDD00";
ctx.globalAlpha = 0.6; ctx.globalAlpha = 0.6;
ctx.beginPath(); ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill(); ctx.fill();
} }
} }
function initParticles() { function initParticles() {
particles = []; particles = [];
for (let i = 0; i < 80; i += 1) { for (let i = 0; i < 80; i += 1) {
particles.push(new Particle()); particles.push(new Particle());
} }
} }
function animateParticles() { function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const particle of particles) { for (const particle of particles) {
particle.update(); particle.update();
particle.draw(); particle.draw();
} }
requestAnimationFrame(animateParticles); requestAnimationFrame(animateParticles);
} }
resizeCanvas(); resizeCanvas();
initParticles(); initParticles();
animateParticles(); animateParticles();
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
resizeCanvas(); resizeCanvas();
initParticles(); initParticles();
}); });
})(); })();
+2 -2
View File
@@ -121,7 +121,7 @@
/** /**
* 站根與 `portal-nav.js` 同層;依腳本路徑與當前頁路徑計算回到站根的相對前綴(如 `../`)。 * 站根與 `portal-nav.js` 同層;依腳本路徑與當前頁路徑計算回到站根的相對前綴(如 `../`)。
* 子資料夾內頁面之導覽連結必須帶此前綴,否則 `./images`、`index.html` 會錯層。 * 子資料夾內頁面之導覽連結必須帶此前綴,否則 `./assets/images`、`index.html` 會錯層。
*/ */
function portalNavRootPrefix() { function portalNavRootPrefix() {
const el = const el =
@@ -150,7 +150,7 @@
/** 全站導覽 HTML — `rp` 為站根相對前綴;僅修改此模板即可同步所有頁面 */ /** 全站導覽 HTML — `rp` 為站根相對前綴;僅修改此模板即可同步所有頁面 */
function buildPortalNavInnerHTML(rp) { function buildPortalNavInnerHTML(rp) {
return ` return `
<a class="logo" href="${rp}index.html"><img src="${rp}images/logov.svg" alt="SECHSKIES Logo"></a> <a class="logo" href="${rp}index.html"><img src="${rp}assets/images/logov.svg" alt="SECHSKIES Logo"></a>
<ul> <ul>
<li><a href="${rp}index.html#origin">淪陷瞬間</a> <li><a href="${rp}index.html#origin">淪陷瞬間</a>
<ul class="portal-submenu"> <ul class="portal-submenu">
+97 -97
View File
@@ -1,97 +1,97 @@
(() => { (() => {
const hubButtons = Array.from(document.querySelectorAll("[data-totoga-hub]")); const hubButtons = Array.from(document.querySelectorAll("[data-totoga-hub]"));
const hubPanels = Array.from(document.querySelectorAll("[data-totoga-panel]")); const hubPanels = Array.from(document.querySelectorAll("[data-totoga-panel]"));
function setHubPanel(name) { function setHubPanel(name) {
hubButtons.forEach((btn) => btn.classList.toggle("active", btn.dataset.totogaHub === name)); hubButtons.forEach((btn) => btn.classList.toggle("active", btn.dataset.totogaHub === name));
hubPanels.forEach((panel) => { hubPanels.forEach((panel) => {
panel.hidden = panel.dataset.totogaPanel !== name; panel.hidden = panel.dataset.totogaPanel !== name;
}); });
} }
hubButtons.forEach((btn) => { hubButtons.forEach((btn) => {
btn.addEventListener("click", () => setHubPanel(btn.dataset.totogaHub)); btn.addEventListener("click", () => setHubPanel(btn.dataset.totogaHub));
}); });
const reader = document.getElementById("totoga2-reader"); const reader = document.getElementById("totoga2-reader");
if (!reader) return; if (!reader) return;
const chapters = Array.from(reader.querySelectorAll(".chronicle-chapter")); const chapters = Array.from(reader.querySelectorAll(".chronicle-chapter"));
const modeButtons = Array.from(document.querySelectorAll("[data-totoga-reader-mode]")); const modeButtons = Array.from(document.querySelectorAll("[data-totoga-reader-mode]"));
const pager = document.getElementById("totoga2-pager"); const pager = document.getElementById("totoga2-pager");
const prevBtn = document.getElementById("totoga2-prev"); const prevBtn = document.getElementById("totoga2-prev");
const nextBtn = document.getElementById("totoga2-next"); const nextBtn = document.getElementById("totoga2-next");
const indicator = document.getElementById("totoga2-chapter-indicator"); const indicator = document.getElementById("totoga2-chapter-indicator");
if (!pager || !prevBtn || !nextBtn || !indicator) return; if (!pager || !prevBtn || !nextBtn || !indicator) return;
let currentIndex = 0; let currentIndex = 0;
function updatePagedView() { function updatePagedView() {
chapters.forEach((chapter, index) => { chapters.forEach((chapter, index) => {
chapter.style.display = index === currentIndex ? "" : "none"; chapter.style.display = index === currentIndex ? "" : "none";
chapter.classList.toggle("active", index === currentIndex); chapter.classList.toggle("active", index === currentIndex);
}); });
indicator.textContent = `${currentIndex + 1} / ${chapters.length}`; indicator.textContent = `${currentIndex + 1} / ${chapters.length}`;
prevBtn.disabled = currentIndex === 0; prevBtn.disabled = currentIndex === 0;
nextBtn.disabled = currentIndex === chapters.length - 1; nextBtn.disabled = currentIndex === chapters.length - 1;
} }
function setReaderMode(mode) { function setReaderMode(mode) {
reader.dataset.mode = mode; reader.dataset.mode = mode;
modeButtons.forEach((btn) => btn.classList.toggle("active", btn.dataset.totogaReaderMode === mode)); modeButtons.forEach((btn) => btn.classList.toggle("active", btn.dataset.totogaReaderMode === mode));
if (mode === "paged") { if (mode === "paged") {
pager.hidden = false; pager.hidden = false;
updatePagedView(); updatePagedView();
} else { } else {
pager.hidden = true; pager.hidden = true;
chapters.forEach((chapter) => { chapters.forEach((chapter) => {
chapter.style.display = ""; chapter.style.display = "";
chapter.classList.remove("active"); chapter.classList.remove("active");
}); });
} }
} }
modeButtons.forEach((button) => { modeButtons.forEach((button) => {
button.addEventListener("click", () => setReaderMode(button.dataset.totogaReaderMode)); button.addEventListener("click", () => setReaderMode(button.dataset.totogaReaderMode));
}); });
prevBtn.addEventListener("click", () => { prevBtn.addEventListener("click", () => {
if (currentIndex > 0) { if (currentIndex > 0) {
currentIndex -= 1; currentIndex -= 1;
updatePagedView(); updatePagedView();
} }
}); });
nextBtn.addEventListener("click", () => { nextBtn.addEventListener("click", () => {
if (currentIndex < chapters.length - 1) { if (currentIndex < chapters.length - 1) {
currentIndex += 1; currentIndex += 1;
updatePagedView(); updatePagedView();
} }
}); });
const initialHub = const initialHub =
hubButtons.find((b) => b.classList.contains("active"))?.dataset.totogaHub || hubButtons.find((b) => b.classList.contains("active"))?.dataset.totogaHub ||
hubButtons[0]?.dataset.totogaHub || hubButtons[0]?.dataset.totogaHub ||
"video"; "video";
setHubPanel(initialHub); setHubPanel(initialHub);
setReaderMode("scroll"); setReaderMode("scroll");
function applyLocationHashNavigation() { function applyLocationHashNavigation() {
const hash = (location.hash || "").slice(1); const hash = (location.hash || "").slice(1);
if (hash === "ebook") { if (hash === "ebook") {
setHubPanel("ebook"); setHubPanel("ebook");
return; return;
} }
if (hash && document.getElementById(hash)) { if (hash && document.getElementById(hash)) {
setHubPanel("reader"); setHubPanel("reader");
setReaderMode("scroll"); setReaderMode("scroll");
pager.hidden = true; pager.hidden = true;
requestAnimationFrame(() => { requestAnimationFrame(() => {
document.getElementById(hash)?.scrollIntoView({ behavior: "smooth", block: "start" }); document.getElementById(hash)?.scrollIntoView({ behavior: "smooth", block: "start" });
}); });
} }
} }
applyLocationHashNavigation(); applyLocationHashNavigation();
window.addEventListener("hashchange", applyLocationHashNavigation); window.addEventListener("hashchange", applyLocationHashNavigation);
})(); })();
+8 -8
View File
@@ -5,10 +5,10 @@
<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="../assets/css/concert.css">
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../assets/css/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">
<link rel="stylesheet" href="../tablet.css"> <link rel="stylesheet" href="../assets/css/tablet.css">
</head> </head>
<body class="concert-page"> <body class="concert-page">
@@ -33,7 +33,7 @@
<div class="con-1" data-tour=" YELLOW NOTE"> <div class="con-1" data-tour=" YELLOW NOTE">
<span class="title">2016&nbsp;&nbsp;|&nbsp;&nbsp;YELLOW NOTE&nbsp;&nbsp;首場回歸演唱會</span> <span class="title">2016&nbsp;&nbsp;|&nbsp;&nbsp;YELLOW NOTE&nbsp;&nbsp;首場回歸演唱會</span>
<img src="../images/concert/2016.jpg" alt=""> <img src="../assets/images/concert/2016.jpg" alt="">
<div class="con-yk-1 attended" data-date1="09.10"> <div class="con-yk-1 attended" data-date1="09.10">
<span class="location">首爾 | 首爾奧林匹克體操競技場</span> <span class="location">首爾 | 首爾奧林匹克體操競技場</span>
<input type="checkbox" id="expand-yk-1" class="expand-trigger"> <input type="checkbox" id="expand-yk-1" class="expand-trigger">
@@ -160,7 +160,7 @@
<div class="con-2" data-tour="20TH ANNIV."> <div class="con-2" data-tour="20TH ANNIV.">
<span class="title">2017-2018&nbsp;&nbsp;|&nbsp;&nbsp;20TH ANNIVERSARY</span> <span class="title">2017-2018&nbsp;&nbsp;|&nbsp;&nbsp;20TH ANNIVERSARY</span>
<img src="../images/concert/2017.jpg" alt=""> <img src="../assets/images/concert/2017.jpg" alt="">
<div class="con-2-1"> <div class="con-2-1">
<span class="location">首爾:高尺天空巨蛋</span> <span class="location">首爾:高尺天空巨蛋</span>
@@ -352,7 +352,7 @@
<!-- 演唱會 03 --> <!-- 演唱會 03 -->
<div class="con-3" data-tour="NOW・HERE・AGAIN."> <div class="con-3" data-tour="NOW・HERE・AGAIN.">
<span class="title">2018&nbsp;&nbsp;|&nbsp;&nbsp;NOW・HERE・AGAIN</span> <span class="title">2018&nbsp;&nbsp;|&nbsp;&nbsp;NOW・HERE・AGAIN</span>
<img src="../images/concert/2018.jpg" alt=""> <img src="../assets/images/concert/2018.jpg" alt="">
<div class="con-3-1 attended" data-date1="10.13" data-date2="10.14"> <div class="con-3-1 attended" data-date1="10.13" data-date2="10.14">
<span class="location">首爾:首爾奧林匹克體操競技場</span> <span class="location">首爾:首爾奧林匹克體操競技場</span>
<input type="checkbox" id="expand-con-3-1" class="expand-trigger"> <input type="checkbox" id="expand-con-3-1" class="expand-trigger">
@@ -389,7 +389,7 @@
<!-- 演唱會 04:與 con-2/con-3 同結構 — title → img → con-4-1;ACCESS 樣式用 con-access-denied;CANCELED 水印為 ::before(::after 保留給 data-tour 緞帶) --> <!-- 演唱會 04:與 con-2/con-3 同結構 — title → img → con-4-1;ACCESS 樣式用 con-access-denied;CANCELED 水印為 ::before(::after 保留給 data-tour 緞帶) -->
<div class="con-4 con-access-denied" data-tour="ACCESS"> <div class="con-4 con-access-denied" data-tour="ACCESS">
<span class="title">2020&nbsp;&nbsp;|&nbsp;&nbsp;CONCERT [ACCESS]</span> <span class="title">2020&nbsp;&nbsp;|&nbsp;&nbsp;CONCERT [ACCESS]</span>
<img src="../images/concert/2020.jpg" alt=""> <img src="../assets/images/concert/2020.jpg" alt="">
<div class="con-4-1 canceled" data-date1="03.06" data-date2="03.08"> <div class="con-4-1 canceled" data-date1="03.06" data-date2="03.08">
<span class="location">首爾:慶熙大學 平和殿堂</span> <span class="location">首爾:慶熙大學 平和殿堂</span>
@@ -631,7 +631,7 @@
init(); init();
animate(); animate();
</script> </script>
<script src="../portal-nav.js"></script> <script src="../assets/js/portal-nav.js"></script>
</body> </body>
</html> </html>
+17 -11
View File
@@ -1,16 +1,16 @@
# 全站導覽列規則(`portal-nav.js`) # 全站導覽列規則(`assets/js/portal-nav.js`)
之後**每新增一個要上線、可點的 HTML 頁面**,請一併完成導覽更新;規則都集中在 **`portal-nav.js`**。 之後**每新增一個要上線、可點的 HTML 頁面**,請一併完成導覽更新;規則都集中在 **`assets/js/portal-nav.js`**。
--- ---
## 1. 必做:把頁面掛進導覽 HTML ## 1. 必做:把頁面掛進導覽 HTML
在 **`buildPortalNavInnerHTML`**(`portal-nav.js`)裡維護連結: 在 **`buildPortalNavInnerHTML`**(`assets/js/portal-nav.js`)裡維護連結:
- 依資訊架構放在對應的 **`<li>`** 底下;需要子選單時用 **`portal-submenu`**。 - 依資訊架構放在對應的 **`<li>`** 底下;需要子選單時用 **`portal-submenu`**。
- `href` 使用**站根相對路徑**(腳本會依當前頁深度加上前綴 `rp`):例如 `` `${rp}variety/variety.html` ``、`` `${rp}index.html#section` ``。 - `href` 使用**站根相對路徑**(腳本會依當前頁深度加上前綴 `rp`):例如 `` `${rp}variety/variety.html` ``、`` `${rp}index.html#section` ``。
- Logo 列:`` `${rp}index.html` `` 與 `` `${rp}images/logov.svg` ``。 - Logo 列:`` `${rp}index.html` `` 與 `` `${rp}assets/images/logov.svg` ``。
新增或調整完後,所有帶 **`data-portal-nav`** 的 `<nav class="portal-nav">` 都會在載入腳本時被注入同一份 HTML。 新增或調整完後,所有帶 **`data-portal-nav`** 的 `<nav class="portal-nav">` 都會在載入腳本時被注入同一份 HTML。
@@ -27,10 +27,10 @@
| 需求 | 做法 | | 需求 | 做法 |
|------|------| |------|------|
| 新頁要**正式開放** | 寫進 `PORTAL_NAV_INNER_HTML`,並**確認檔名不在** `COMING_SOON_PAGES`。若曾暫時關閉,記得從 Set **刪除**該檔名。 | | 新頁要**正式開放** | 寫進 `buildPortalNavInnerHTML`(`assets/js/portal-nav.js`),並**確認檔名不在** `COMING_SOON_PAGES`。若曾暫時關閉,記得從 Set **刪除**該檔名。 |
| 新頁先**占位、不開放** | 可選擇:仍寫進導覽,但把檔名**加進** `COMING_SOON_PAGES`;或暫時不要放進導覽。 | | 新頁先**占位、不開放** | 可選擇:仍寫進導覽,但把檔名**加進** `COMING_SOON_PAGES`;或暫時不要放進導覽。 |
(目前 Set 內含哪些檔,以 `portal-nav.js` 為準;例如 `totoga2.html` 若已開放,就不應出現在 Set 裡。) (目前 Set 內含哪些檔,以 `assets/js/portal-nav.js` 為準;例如 `totoga2.html` 若已開放,就不應出現在 Set 裡。)
--- ---
@@ -54,16 +54,22 @@
- 在 `</body>` 前載入(順序可與現有頁一致): - 在 `</body>` 前載入(順序可與現有頁一致):
```html ```html
<script src="portal-nav.js"></script> <script src="assets/js/portal-nav.js"></script>
``` ```
- 若該頁有 **`particles.js`**/共用樣式,比照其他內頁一併引入即可。 內頁(例如 `extra/`、`variety/` 下)請用相對站根深度,例如:
```html
<script src="../assets/js/portal-nav.js"></script>
```
- 若該頁有 **`assets/js/particles.js`**/共用樣式(`assets/css/style.css` 等),比照其他內頁一併引入即可。
--- ---
## 5. 刻意不進導覽的頁面 ## 5. 刻意不進導覽的頁面
若某頁只給自己用(例如站內索引、草稿),**不要**寫進 `PORTAL_NAV_INNER_HTML` 即可;不必改 `COMING_SOON_PAGES`。 若某頁只給自己用(例如站內索引、草稿),**不要**寫進 `buildPortalNavInnerHTML` 即可;不必改 `COMING_SOON_PAGES`。
--- ---
@@ -86,7 +92,7 @@
| 檔案 | 用途 | | 檔案 | 用途 |
|------|------| |------|------|
| `portal-nav.js` | `PORTAL_NAV_INNER_HTML`、`COMING_SOON_PAGES`、`INDEX_NAV_OPEN_HASHES`、籌備中邏輯 | | `assets/js/portal-nav.js` | `buildPortalNavInnerHTML`、`COMING_SOON_PAGES`、`INDEX_NAV_OPEN_HASHES`、籌備中邏輯 |
| `style.css` | `.portal-nav`、子選單、`.nav-current` 等樣式 | | `assets/css/style.css` | `.portal-nav`、子選單、`.nav-current` 等樣式 |
(導覽文案隨機句:`NAV_SOON_PHRASES`,僅影響籌備中連結的提示,與新頁是否開放無關。) (導覽文案隨機句:`NAV_SOON_PHRASES`,僅影響籌備中連結的提示,與新頁是否開放無關。)
+3 -3
View File
@@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>水晶男孩 SECHSKIES | 永恆的六顆水晶</title> <title>水晶男孩 SECHSKIES | 永恆的六顆水晶</title>
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../assets/css/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">
<link rel="stylesheet" href="../tablet.css"> <link rel="stylesheet" href="../assets/css/tablet.css">
</head> </head>
<body> <body>
@@ -47,7 +47,7 @@
<h2>六位永恆成員</h2> <h2>六位永恆成員</h2>
<div class="members-grid"> <div class="members-grid">
<div class="member"> <div class="member">
<img src="../images/Eun Ji Won.jpeg" alt="殷志源"> <img src="../assets/images/Eun Ji Won.jpeg" alt="殷志源">
<h3>殷志源 (Eun Ji Won)</h3> <h3>殷志源 (Eun Ji Won)</h3>
<p>Leader • Rap • Black Kies</p> <p>Leader • Rap • Black Kies</p>
</div> </div>
+3 -3
View File
@@ -9,9 +9,9 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="lyrics.css"> <link rel="stylesheet" href="../assets/css/lyrics.css">
<link rel="stylesheet" href="../tablet.css"> <link rel="stylesheet" href="../assets/css/tablet.css">
</head> </head>
<body class="lyrics-page"> <body class="lyrics-page">
+11 -11
View File
@@ -5,9 +5,9 @@
<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>水晶男孩推廣部|視覺進化論</title> <title>水晶男孩推廣部|視覺進化論</title>
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../assets/css/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">
<link rel="stylesheet" href="../tablet.css"> <link rel="stylesheet" href="../assets/css/tablet.css">
</head> </head>
<body class="chronicle-page minister-page"> <body class="chronicle-page minister-page">
@@ -60,25 +60,25 @@
<p class="minister-month">07 月|手作初試</p> <p class="minister-month">07 月|手作初試</p>
<p>開始學習勾針,為金在德製作第一個鴨鴨置物籃,這是從旁觀者轉為實踐者的第一步。</p> <p>開始學習勾針,為金在德製作第一個鴨鴨置物籃,這是從旁觀者轉為實踐者的第一步。</p>
<figure class="minister-photo"> <figure class="minister-photo">
<img src="../images/minister/image_3c1739.jpg" alt="手作鴨鴨置物籃" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3c1739.jpg" alt="手作鴨鴨置物籃" width="1040" height="780" loading="lazy">
</figure> </figure>
<p class="minister-month">08 月|螢幕後的參與</p> <p class="minister-month">08 月|螢幕後的參與</p>
<p>以「水晶廢人字幕組」粉絲身分,用手繪應援板與勾針作品參與應援影片籌備。</p> <p>以「水晶廢人字幕組」粉絲身分,用手繪應援板與勾針作品參與應援影片籌備。</p>
<figure class="minister-photo"> <figure class="minister-photo">
<img src="../images/minister/image_3c13d7.jpg" alt="手繪應援板與勾針作品" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3c13d7.jpg" alt="手繪應援板與勾針作品" width="1040" height="780" loading="lazy">
</figure> </figure>
<p class="minister-month">09 月|孤注一擲的現場</p> <p class="minister-month">09 月|孤注一擲的現場</p>
<p>在經濟窘迫、甚至需要借錢籌措旅費的情況下,飛往首爾參加首場演唱會。在那裡,我握著導師設計的台灣小黃手幅,第一次感受到設計與才華帶來的震撼。</p> <p>在經濟窘迫、甚至需要借錢籌措旅費的情況下,飛往首爾參加首場演唱會。在那裡,我握著導師設計的台灣小黃手幅,第一次感受到設計與才華帶來的震撼。</p>
<figure class="minister-photo"> <figure class="minister-photo">
<img src="../images/minister/image_3bb254.jpg" alt="台灣小黃手幅" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3bb254.jpg" alt="台灣小黃手幅" width="1040" height="780" loading="lazy">
</figure> </figure>
<p class="minister-month">12 月|溫暖的饋贈</p> <p class="minister-month">12 月|溫暖的饋贈</p>
<p>在「#水晶文具社」聚會中,收到了同好精緻的手繪聖誕卡片。看著別人的創作,我更加確信自己也想成為能用作品傳遞能量的人。</p> <p>在「#水晶文具社」聚會中,收到了同好精緻的手繪聖誕卡片。看著別人的創作,我更加確信自己也想成為能用作品傳遞能量的人。</p>
<figure class="minister-photo"> <figure class="minister-photo">
<img src="../images/minister/image_3bab17.jpg" alt="手繪聖誕卡片" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3bab17.jpg" alt="手繪聖誕卡片" width="1040" height="780" loading="lazy">
</figure> </figure>
</article> </article>
@@ -87,7 +87,7 @@
<p class="minister-month">01 月|職人精神的啟發</p> <p class="minister-month">01 月|職人精神的啟發</p>
<p>參與資管組 D 大的新年紅包活動。其書法與刻印結合的質感,深深影響了我對美感的標準。</p> <p>參與資管組 D 大的新年紅包活動。其書法與刻印結合的質感,深深影響了我對美感的標準。</p>
<figure class="minister-photo"> <figure class="minister-photo">
<img src="../images/minister/image_3ba74f.jpg" alt="新年紅包活動" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3ba74f.jpg" alt="新年紅包活動" width="1040" height="780" loading="lazy">
</figure> </figure>
<p class="minister-month">02 月|身體記憶的熱血</p> <p class="minister-month">02 月|身體記憶的熱血</p>
@@ -96,8 +96,8 @@
<p class="minister-month">04 月|筆尖的沈澱</p> <p class="minister-month">04 月|筆尖的沈澱</p>
<p>跟著文具社走遍全台咖啡廳,在鋼筆墨水與玻璃杯的陪伴下,用手寫記錄初心。</p> <p>跟著文具社走遍全台咖啡廳,在鋼筆墨水與玻璃杯的陪伴下,用手寫記錄初心。</p>
<figure class="minister-photo minister-photo--dual"> <figure class="minister-photo minister-photo--dual">
<img src="../images/minister/image_3baed1.jpg" alt="鋼筆墨水與玻璃杯" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3baed1.jpg" alt="鋼筆墨水與玻璃杯" width="1040" height="780" loading="lazy">
<img src="../images/minister/image_3c2299.jpg" alt="手寫記錄初心" width="1040" height="780" loading="lazy"> <img src="../assets/images/minister/image_3c2299.jpg" alt="手寫記錄初心" width="1040" height="780" loading="lazy">
</figure> </figure>
</article> </article>
@@ -124,8 +124,8 @@
</a> </a>
</footer> </footer>
<script src="../particles.js"></script> <script src="../assets/js/particles.js"></script>
<script src="../portal-nav.js"></script> <script src="../assets/js/portal-nav.js"></script>
</body> </body>
</html> </html>
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff. Show more