diff --git a/.gitignore b/.gitignore index 23f7d09..7916f07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -# 本機圖片備份(勿進 repo) -*.png.bak +# 本機圖片備份(勿進 repo) +*.png.bak diff --git a/albums/albums.html b/albums/albums.html index 4e2a4de..9ec185f 100644 --- a/albums/albums.html +++ b/albums/albums.html @@ -1,150 +1,150 @@ - - - - - - - 水晶男孩|黃色留聲機 - - - - - - - -
-
-

黃色留聲機

-
- YELLOW PHONOGRAPH -
-
-
- - - - - -
-
-

- 音軌才是與這個名字最直白相遇的方式——以下先收精選年表與深水連結。 -

-
- -
-

啟動新篇章

-

回歸後的數位單曲與專輯,是現在進行式的聲紋紀錄;耳機調大聲一格,就能把「新篇章」接住。

-

聽見歌詞細節(2016 代表曲目)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
封面年份專輯/作品主打歌
- 2016 數位單曲 封面 - 2016數位單曲Three Words (三個詞)
- 2017 ANOTHER LIGHT 封面 - 2017ANOTHER LIGHTSomething Special / Smile
- 2020 ALL FOR YOU 封面 - 2020ALL FOR YOUALL FOR YOU
-
- -
-

輝煌全盛期

-

主打的記憶點、b-side 的伏筆、舞步與應援口號——想一次收進收藏庫,往這張整理頁走。

-

於此區瀏覽輝煌全盛期年表

- - - - - - - - - - - - - - - - - - - - - - - - - -
年份專輯/作品主打歌
1997學園別曲學園別曲 / 男兒之路 (Pom Saeng Pom Sa)
1998Road FighterRoad Fighter / Couple
1999Com'BackCom'Back
-
-
- - - - - - - - - + + + + + + + 水晶男孩|黃色留聲機 + + + + + + + +
+
+

黃色留聲機

+
+ YELLOW PHONOGRAPH +
+
+
+ + + + + +
+
+

+ 音軌才是與這個名字最直白相遇的方式——以下先收精選年表與深水連結。 +

+
+ +
+

啟動新篇章

+

回歸後的數位單曲與專輯,是現在進行式的聲紋紀錄;耳機調大聲一格,就能把「新篇章」接住。

+

聽見歌詞細節(2016 代表曲目)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
封面年份專輯/作品主打歌
+ 2016 數位單曲 封面 + 2016數位單曲Three Words (三個詞)
+ 2017 ANOTHER LIGHT 封面 + 2017ANOTHER LIGHTSomething Special / Smile
+ 2020 ALL FOR YOU 封面 + 2020ALL FOR YOUALL FOR YOU
+
+ +
+

輝煌全盛期

+

主打的記憶點、b-side 的伏筆、舞步與應援口號——想一次收進收藏庫,往這張整理頁走。

+

於此區瀏覽輝煌全盛期年表

+ + + + + + + + + + + + + + + + + + + + + + + + + +
年份專輯/作品主打歌
1997學園別曲學園別曲 / 男兒之路 (Pom Saeng Pom Sa)
1998Road FighterRoad Fighter / Couple
1999Com'BackCom'Back
+
+
+ + + + + + + + + diff --git a/assets/css/concert.css b/assets/css/concert.css index af2123e..6c94cf5 100644 --- a/assets/css/concert.css +++ b/assets/css/concert.css @@ -1,5 +1,5 @@ body.concert-page { - background-color: var(--deep-black, #0a0a0a); + background-color: var(--color-bg); margin: 0; padding: 0; } diff --git a/assets/css/index.css b/assets/css/index.css index d24032f..ff8e2fa 100644 --- a/assets/css/index.css +++ b/assets/css/index.css @@ -10,7 +10,7 @@ content: ''; position: absolute; width: 6px; - background-color: var(--primary); + background-color: var(--color-brand); top: 0; bottom: 0; left: 50%; @@ -39,7 +39,7 @@ display: flex; justify-content: center; align-items: center; - color: #FFD700; + color: var(--color-brand); text-shadow: 0 0 8px rgba(255, 215, 0, 0.5); } @@ -61,20 +61,20 @@ .date-tag { display: inline-block; padding: 8px 20px; - background: var(--accent); - color: var(--text); + background: var(--color-brand); + color: var(--color-text-dark); border-radius: 50px; font-weight: bold; margin-bottom: 10px; } .content h3 { - color: var(--primary); + color: var(--color-brand); margin: 10px 0; } .content p { - color: var(--text-muted); + color: var(--color-text-muted); line-height: 1.6; } @@ -158,12 +158,12 @@ section.archive-intro p { /* * 首頁 hero 主標/副標:與全站 .site-header-inner 相同(index.css 在 style.css 之後載入)。 - * 若留舊版 .home-page header .hero h1 { color: var(--primary); text-shadow: … } 會蓋過 style.css。 + * 若留舊版 .home-page header .hero h1 { color: var(--color-brand); text-shadow: … } 會蓋過 style.css。 */ .home-page header#origin .site-header-inner .main-title { font-size: clamp(2rem, 4.5vw, 3.2rem); font-weight: 900; - color: var(--text-main, #333); + color: var(--color-text); letter-spacing: 6px; margin: 0; text-shadow: none; @@ -172,7 +172,7 @@ section.archive-intro p { .home-page header#origin .site-header-inner .sub-title { font-size: 0.92rem; letter-spacing: 4px; - color: var(--text-muted, #888); + color: var(--color-text-muted); text-transform: uppercase; } @@ -282,7 +282,7 @@ header#origin .site-header-inner .subtitle-wrap::after { } .home-page .landing-intro .mark_b { - color: var(--light-yellow); + color: var(--color-brand-light); } .home-page #intro .intro-text .slogan-quote--awakening + .core-description { @@ -365,7 +365,7 @@ header#origin .site-header-inner .subtitle-wrap::after { .home-page #journey .merged-storyline .story-node .journey-month { margin: 0.75rem 0 0.3rem; padding: 0.32rem 0.7rem 0.32rem 0; - border-right: 3px solid var(--primary); + border-right: 3px solid var(--color-brand); border-left: 0; font-size: 0.82rem; font-weight: 800; diff --git a/assets/css/lyrics.css b/assets/css/lyrics.css index 0d20247..3aa2705 100644 --- a/assets/css/lyrics.css +++ b/assets/css/lyrics.css @@ -1,182 +1,182 @@ -/* 歌詞頁:載入於 style.css 之後,並以 .lyrics-page 提高權重,避免被全站 table / body 洗版 */ - -body.lyrics-page { - --lyrics-bg: #2a2a2a; - --lyrics-paper: #faf6e8; - --lyrics-accent: #f5dfa8; - --lyrics-muted: #c9c2a8; - - font-family: "Nanum Pen Script", cursive; - font-weight: 400; - font-style: normal; - background-color: var(--lyrics-bg) !important; - color: #fff !important; - margin: 0 !important; - padding: clamp(1rem, 4vw, 2.5rem) !important; - min-height: 100dvh; - line-height: 1.55; - overflow-x: hidden; - font-size: clamp(18px, 2.8vw, 26px); -} - -body.lyrics-page h1 { - color: var(--lyrics-accent); - font-size: clamp(1.75rem, 4vw, 2.5rem); - text-align: center; - margin: 0 0 1.25rem; - letter-spacing: 0.02em; -} - -body.lyrics-page .lyrics-layout { - max-width: 1100px; - margin: 0 auto; -} - -body.lyrics-page .lyrics-main-table { - width: 100%; - max-width: 1100px; - margin: 0 auto; - table-layout: fixed; - border-collapse: separate; - border-spacing: clamp(0.75rem, 2.5vw, 1.75rem); - background: transparent !important; - box-shadow: none !important; - border-radius: 0 !important; -} - -body.lyrics-page .lyrics-main-table > tbody > tr > td { - padding: 0 !important; - border: none !important; - border-bottom: none !important; - text-align: left !important; - color: inherit !important; - background: transparent !important; -} - -/* 兩欄等寬 + 同一套「卡片区」留白與邊框,左右才對稱 */ -body.lyrics-page .main-left, -body.lyrics-page .lyrics-text-cell, -body.lyrics-page .lyrics-map-cell, -body.lyrics-page .lyrics-contact-cell { - width: 50%; - max-width: none; - box-sizing: border-box; - padding: clamp(0.85rem, 2vw, 1.15rem) clamp(0.9rem, 2.2vw, 1.25rem) !important; - border-radius: 14px; - border: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(0, 0, 0, 0.22); -} - -body.lyrics-page .main-left, -body.lyrics-page .lyrics-text-cell { - vertical-align: top; -} - -body.lyrics-page .lyrics-map-cell { - vertical-align: top; -} - -body.lyrics-page .lyrics-contact-cell { - vertical-align: middle; -} - -body.lyrics-page .main-left iframe { - display: block; - width: 100%; - border: 0; - border-radius: 10px; - box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35); -} - -body.lyrics-page .songInfo { - color: var(--lyrics-accent); - display: grid; - grid-template-columns: max-content 1fr; - gap: 0.4rem 0.75rem; - align-items: baseline; - font-size: 1rem; - margin-top: 1rem; -} - -body.lyrics-page .songInfo dt { - font-weight: 700; - color: var(--lyrics-muted); -} - -body.lyrics-page .songInfo dd { - margin: 0; -} - -body.lyrics-page .lyrics-main-table p { - color: #fff; - line-height: 1.55; - font-size: clamp(1rem, 2.2vw, 1.35rem); - margin: 0; -} - -body.lyrics-page .lyrics-map-cell iframe { - box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35); -} - -body.lyrics-page .lyrics-contact-cell .contact { - margin-top: 0; -} - -body.lyrics-page a { - color: #b8e6ff; - text-decoration: underline; - text-underline-offset: 0.15em; -} - -body.lyrics-page a:hover { - color: #fff; -} - -body.lyrics-page .contact { - color: var(--lyrics-paper); - font-size: 0.95rem; - line-height: 1.65; -} - -body.lyrics-page .contact h3 { - color: var(--lyrics-accent); - font-size: 1.15rem; - margin: 0.35rem 0 0.5rem; - font-family: "Nanum Pen Script", cursive; -} - -body.lyrics-page .contact img { - max-height: 36px; - width: auto; - display: block; - margin-bottom: 0.35rem; -} - -body.lyrics-page .contact i { - font-size: 0.75em; - margin-right: 0.35rem; - color: var(--lyrics-accent); -} - -@media (max-width: 820px) { - body.lyrics-page .lyrics-main-table, - body.lyrics-page .lyrics-main-table tbody, - body.lyrics-page .lyrics-main-table tr, - body.lyrics-page .lyrics-main-table td { - display: block; - width: 100% !important; - } - - body.lyrics-page .lyrics-main-table { - border-spacing: 0; - } - - body.lyrics-page .main-left { - max-width: none; - margin-bottom: 1.5rem; - } - - body.lyrics-page .lyrics-main-table > tbody > tr > td + td { - margin-top: 0.5rem; - } -} +/* 歌詞頁:載入於 style.css 之後,並以 .lyrics-page 提高權重,避免被全站 table / body 洗版 */ + +body.lyrics-page { + --lyrics-bg: #2a2a2a; + --lyrics-paper: #faf6e8; + --lyrics-accent: #f5dfa8; + --lyrics-muted: #c9c2a8; + + font-family: "Nanum Pen Script", cursive; + font-weight: 400; + font-style: normal; + background-color: var(--lyrics-bg) !important; + color: #fff !important; + margin: 0 !important; + padding: clamp(1rem, 4vw, 2.5rem) !important; + min-height: 100dvh; + line-height: 1.55; + overflow-x: hidden; + font-size: clamp(18px, 2.8vw, 26px); +} + +body.lyrics-page h1 { + color: var(--lyrics-accent); + font-size: clamp(1.75rem, 4vw, 2.5rem); + text-align: center; + margin: 0 0 1.25rem; + letter-spacing: 0.02em; +} + +body.lyrics-page .lyrics-layout { + max-width: 1100px; + margin: 0 auto; +} + +body.lyrics-page .lyrics-main-table { + width: 100%; + max-width: 1100px; + margin: 0 auto; + table-layout: fixed; + border-collapse: separate; + border-spacing: clamp(0.75rem, 2.5vw, 1.75rem); + background: transparent !important; + box-shadow: none !important; + border-radius: 0 !important; +} + +body.lyrics-page .lyrics-main-table > tbody > tr > td { + padding: 0 !important; + border: none !important; + border-bottom: none !important; + text-align: left !important; + color: inherit !important; + background: transparent !important; +} + +/* 兩欄等寬 + 同一套「卡片区」留白與邊框,左右才對稱 */ +body.lyrics-page .main-left, +body.lyrics-page .lyrics-text-cell, +body.lyrics-page .lyrics-map-cell, +body.lyrics-page .lyrics-contact-cell { + width: 50%; + max-width: none; + box-sizing: border-box; + padding: clamp(0.85rem, 2vw, 1.15rem) clamp(0.9rem, 2.2vw, 1.25rem) !important; + border-radius: 14px; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(0, 0, 0, 0.22); +} + +body.lyrics-page .main-left, +body.lyrics-page .lyrics-text-cell { + vertical-align: top; +} + +body.lyrics-page .lyrics-map-cell { + vertical-align: top; +} + +body.lyrics-page .lyrics-contact-cell { + vertical-align: middle; +} + +body.lyrics-page .main-left iframe { + display: block; + width: 100%; + border: 0; + border-radius: 10px; + box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35); +} + +body.lyrics-page .songInfo { + color: var(--lyrics-accent); + display: grid; + grid-template-columns: max-content 1fr; + gap: 0.4rem 0.75rem; + align-items: baseline; + font-size: 1rem; + margin-top: 1rem; +} + +body.lyrics-page .songInfo dt { + font-weight: 700; + color: var(--lyrics-muted); +} + +body.lyrics-page .songInfo dd { + margin: 0; +} + +body.lyrics-page .lyrics-main-table p { + color: #fff; + line-height: 1.55; + font-size: clamp(1rem, 2.2vw, 1.35rem); + margin: 0; +} + +body.lyrics-page .lyrics-map-cell iframe { + box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35); +} + +body.lyrics-page .lyrics-contact-cell .contact { + margin-top: 0; +} + +body.lyrics-page a { + color: #b8e6ff; + text-decoration: underline; + text-underline-offset: 0.15em; +} + +body.lyrics-page a:hover { + color: #fff; +} + +body.lyrics-page .contact { + color: var(--lyrics-paper); + font-size: 0.95rem; + line-height: 1.65; +} + +body.lyrics-page .contact h3 { + color: var(--lyrics-accent); + font-size: 1.15rem; + margin: 0.35rem 0 0.5rem; + font-family: "Nanum Pen Script", cursive; +} + +body.lyrics-page .contact img { + max-height: 36px; + width: auto; + display: block; + margin-bottom: 0.35rem; +} + +body.lyrics-page .contact i { + font-size: 0.75em; + margin-right: 0.35rem; + color: var(--lyrics-accent); +} + +@media (max-width: 820px) { + body.lyrics-page .lyrics-main-table, + body.lyrics-page .lyrics-main-table tbody, + body.lyrics-page .lyrics-main-table tr, + body.lyrics-page .lyrics-main-table td { + display: block; + width: 100% !important; + } + + body.lyrics-page .lyrics-main-table { + border-spacing: 0; + } + + body.lyrics-page .main-left { + max-width: none; + margin-bottom: 1.5rem; + } + + body.lyrics-page .lyrics-main-table > tbody > tr > td + td { + margin-top: 0.5rem; + } +} diff --git a/assets/css/style.css b/assets/css/style.css index ecde5e2..6b3ed12 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -1,22 +1,25 @@ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@100..900&display=swap'); :root { - --primary: #ffcc00; - --light-yellow: #fceea7; - --dark-yellow: #4e492b; - --black: #1a1a1a; - --deep-black: #0a0a0a; - --gray: #f4f4f4; - --text-color: #333; - --accent: #FFD700; - --text: #1a1a1a; - --card-bg: #1a1a1a; - --bg-alt: #fcfaf2; - --text-main: #333; - --text-muted: #4d4d4d; - --surface: #fffdf7; - --surface-soft: #fff9e8; + /* ── 品牌色 ── */ + --color-brand: #ffcc00; + --color-brand-light: #fceea7; + --color-brand-dark: #4e492b; + /* ── 背景色 ── */ + --color-bg: #0a0a0a; + --color-bg-raised: #1a1a1a; + --color-bg-alt: #fcfaf2; + + /* ── 表面色(淺色內容區) ── */ + --color-surface: #fffdf7; + --color-surface-soft: #fff9e8; + + /* ── 文字色 ── */ + --color-text: #333333; + --color-text-dark: #1a1a1a; + --color-text-muted: #4d4d4d; + --color-text-inverse: #f4f4f4; } /* 1. 先處理 body 和全域,確保沒人亂給外距 */ @@ -29,7 +32,7 @@ html, body { - background-color: var(--deep-black); + background-color: var(--color-bg); color: #eeeeee; height: 100%; margin: 0; @@ -39,7 +42,7 @@ body { body { font-family: 'Noto Sans TC', system-ui, sans-serif; - color: var(--text-color); + color: var(--color-text); line-height: 1.6; } @@ -63,7 +66,7 @@ header#origin { /* 導覽列(排除 portal、B 站分集 tab 等自帶版面之 nav,避免 space-between/大 padding 破壞) */ nav:not(.portal-nav):not(.bilivideo-episode-nav) { - background-color: var(--black); + background-color: var(--color-bg-raised); padding: 0.8rem; display: flex; justify-content: space-between; @@ -120,7 +123,7 @@ nav a { width: 100%; margin: 0 0 14px; padding: 0.8rem 100px; - background-color: var(--black); + background-color: var(--color-bg-raised); border-radius: 0; box-shadow: none; overflow: visible; @@ -144,11 +147,11 @@ nav a { border-radius: 10px; background: transparent; cursor: pointer; - color: var(--primary); + color: var(--color-brand); } .portal-nav__menu-toggle:focus-visible { - outline: 2px solid var(--primary); + outline: 2px solid var(--color-brand); outline-offset: 3px; } @@ -211,7 +214,7 @@ nav a { text-align: center; line-height: 1.15; text-decoration: none; - color: var(--primary); + color: var(--color-brand); font-size: 0.95rem; letter-spacing: 1px; padding: 2px 4px; @@ -482,7 +485,7 @@ nav a { max(0.85rem, env(safe-area-inset-top, 0px)) clamp(14px, 2vw + 10px, 32px) max(1rem, env(safe-area-inset-bottom, 0px)); z-index: 10000; overflow: hidden; - background-color: var(--black); + background-color: var(--color-bg-raised); grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); grid-template-areas: @@ -498,7 +501,7 @@ nav a { position: relative; z-index: 2; flex-shrink: 0; - background-color: var(--black); + background-color: var(--color-bg-raised); } .portal-nav .logo { @@ -599,7 +602,7 @@ nav a { .portal-nav.portal-nav--open>ul>li.open>a { border-color: transparent; border-radius: 0; - color: var(--primary); + color: var(--color-brand); } .portal-nav>ul>li { @@ -972,13 +975,13 @@ footer { .hero p { font-size: 1.2rem; - color: var(--gray); + color: var(--color-text-inverse); } .btn { display: inline-block; padding: 10px 30px; - background: var(--primary); + background: var(--color-brand); color: #000; font-weight: bold; border-radius: 50px; @@ -1007,7 +1010,7 @@ footer { } .section-title { - color: var(--primary); + color: var(--color-brand); text-align: center; font-size: 1.35rem; letter-spacing: 3px; @@ -1020,7 +1023,7 @@ footer { display: block; width: 50px; height: 3px; - background: var(--primary); + background: var(--color-brand); margin: 15px auto 0; } @@ -1036,7 +1039,7 @@ footer { content: ""; flex: 1; height: 2px; - background-color: var(--primary); + background-color: var(--color-brand); max-width: 56px; opacity: 0.7; } @@ -1059,7 +1062,7 @@ footer { } .card { - background: linear-gradient(135deg, var(--surface-soft) 0%, #ffffff 100%); + background: linear-gradient(135deg, var(--color-surface-soft) 0%, #ffffff 100%); backdrop-filter: blur(10px); border: 1px solid rgba(255, 204, 0, 0.18); border-radius: 14px; @@ -1070,7 +1073,7 @@ footer { .card:hover { transform: translateY(-8px); - border-color: var(--primary); + border-color: var(--color-brand); box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14); } @@ -1087,7 +1090,7 @@ footer { section { margin-top: 0 !important; margin-bottom: 60px; - background: var(--surface); + background: var(--color-surface); padding: 44px 36px; border-radius: 16px; border: 1px solid rgba(255, 204, 0, 0.15); @@ -1153,14 +1156,14 @@ section { width: 3.25rem; height: 4px; margin: 0.55rem 0 0; - background: linear-gradient(90deg, var(--primary), #ffe066); + background: linear-gradient(90deg, var(--color-brand), #ffe066); border-radius: 2px; } .mission-section .mission-logo-heading { font-size: 1.08rem; letter-spacing: 0.18em; - color: var(--primary); + color: var(--color-brand); margin: 0 0 0.85rem; font-weight: 800; text-transform: uppercase; @@ -1199,7 +1202,7 @@ section { overflow: hidden; border: 1px solid rgba(255, 204, 0, 0.28); box-shadow: 0 10px 28px rgba(0, 0, 0, 0.12); - background: #1a1a1a; + background: var(--color-bg-raised); } .mission-section .mission-gif-frame img { @@ -1281,7 +1284,7 @@ section { flex-shrink: 0; font-size: 0.95rem; line-height: 1; - color: var(--primary); + color: var(--color-brand); font-style: normal; } @@ -1338,7 +1341,7 @@ section { top: 0.15em; font-size: 1.05em; line-height: 1; - color: var(--fa-before-color, var(--primary, #ffcc00)); + color: var(--fa-before-color, var(--color-brand)); } .fa-before-lead.fa-before-lead--balloon::before { @@ -1347,7 +1350,7 @@ section { width: 1.15em; height: 1.15em; top: 0.1em; - background-color: var(--fa-before-color, var(--primary, #ffcc00)); + background-color: var(--fa-before-color, var(--color-brand)); -webkit-mask: url('../images/icon/balloon.svg') center / contain no-repeat; mask: url('../images/icon/balloon.svg') center / contain no-repeat; } @@ -1383,7 +1386,7 @@ section { content: ""; flex: 1; height: 2px; - background-color: var(--primary); + background-color: var(--color-brand); max-width: 56px; opacity: 0.7; } @@ -1419,7 +1422,7 @@ section { linear-gradient(185deg, rgba(255, 255, 255, 0.65) 0%, rgba(255, 255, 255, 0) 42%), linear-gradient(168deg, #fffef8 0%, #fff6d2 52%, #fffce8 100%); border: 1px solid rgba(220, 185, 90, 0.42); - border-left: 5px solid var(--primary); + border-left: 5px solid var(--color-brand); border-radius: 14px; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.92) inset, @@ -1463,8 +1466,8 @@ table { } table th { - background-color: var(--primary); - color: var(--black); + background-color: var(--color-brand); + color: var(--color-bg-raised); padding: 12px; } @@ -1476,7 +1479,7 @@ table td { } a { - color: var(--text-color); + color: var(--color-text); text-decoration: none; } @@ -1518,7 +1521,7 @@ a { max-width: 42rem; margin: 0 0 28px; padding: 16px 18px; - background: linear-gradient(135deg, var(--surface-soft) 0%, #fff 100%); + background: linear-gradient(135deg, var(--color-surface-soft) 0%, #fff 100%); border: 1px solid rgba(255, 204, 0, 0.18); border-radius: 12px; box-shadow: 0 10px 24px rgba(0, 0, 0, 0.1); @@ -1560,7 +1563,7 @@ a { content: attr(data-era); position: absolute; top: -14px; - background-color: var(--primary); + background-color: var(--color-brand); color: #303030; font-size: 0.7rem; font-weight: 700; @@ -1701,7 +1704,7 @@ a { } .merged-storyline .timeline-ebook-cta:focus-visible { - outline: 3px solid #1a1a1a; + outline: 3px solid var(--color-bg-raised); outline-offset: 3px; } @@ -1802,7 +1805,7 @@ a { .merged-storyline .story-external-inline:hover, .merged-storyline .story-external-inline:focus-visible { - color: var(--dark-yellow); + color: var(--color-brand-dark); } .merged-storyline .story-external-inline i { @@ -1861,7 +1864,7 @@ a { /* 頁尾 */ footer { - background-color: var(--black); + background-color: var(--color-bg-raised); color: white; text-align: center; padding: 50px 0 20px; @@ -1869,13 +1872,13 @@ footer { /* 全站:深色字重點(棕黃字色,與 不同於「顏色」) */ .mark_b { - color: var(--dark-yellow); + color: var(--color-brand-dark); font-weight: bold; } /* 深色頁尾內的 mark_b:維持可讀與全站黃色語彙 */ footer a .mark_b { - color: var(--primary); + color: var(--color-brand); } /* map.html — 主內容層;頂欄見全站 .portal-nav */ @@ -1921,7 +1924,7 @@ footer a .mark_b { align-items: flex-end; text-align: right; white-space: normal; - color: var(--primary); + color: var(--color-brand); text-decoration: none; font-size: 0.95rem; letter-spacing: 1px; @@ -2196,7 +2199,7 @@ header.inner-page-header .sub-title { .site-header-inner .main-title { font-size: clamp(2rem, 4.5vw, 3.2rem); font-weight: 900; - color: var(--text-main, #333); + color: var(--color-text); letter-spacing: 6px; margin: 0; text-shadow: none; @@ -2228,7 +2231,7 @@ header.inner-page-header .sub-title { flex: 0 0 auto; font-size: 0.92rem; letter-spacing: 4px; - color: var(--text-muted, #888); + color: var(--color-text-muted); margin: 0 18px; text-transform: uppercase; } @@ -2268,7 +2271,7 @@ header.inner-page-header .sub-title { } #itinerary-search:focus { - border-color: #ffcc00; + border-color: var(--color-brand); box-shadow: 0 0 0 3px rgba(255, 204, 0, 0.2); } @@ -2287,9 +2290,9 @@ header.inner-page-header .sub-title { .tab-btn:hover, .tab-btn.active { - background: #ffcc00; + background: var(--color-brand); color: #2f2f2f; - border-color: #ffcc00; + border-color: var(--color-brand); } .map-sticky { @@ -2641,7 +2644,7 @@ header.inner-page-header .sub-title { } .mode-btn.active { - background: var(--primary); + background: var(--color-brand); color: #161616; } @@ -3111,7 +3114,7 @@ body.totoga2-page .totoga2-plot .intro-text { } body.totoga2-page .totoga2-plot .intro-text a { - color: var(--dark-yellow); + color: var(--color-brand-dark); font-weight: 700; text-decoration: underline; } @@ -3257,7 +3260,7 @@ body.member-crystal-page .member-crystal-intro__title { } body.member-crystal-page .member-crystal-intro--black .member-crystal-intro__title { - color: var(--yellow); + color: var(--color-brand); } body.member-crystal-page .member-crystal-intro__en { @@ -3677,7 +3680,7 @@ body.site-guide-page .site-guide-grid { } body.site-guide-page .site-guide-card { - background: linear-gradient(135deg, var(--surface-soft) 0%, #fff 100%); + background: linear-gradient(135deg, var(--color-surface-soft) 0%, #fff 100%); border-radius: 14px; padding: 1.25rem 1.35rem; border: 1px solid rgba(255, 204, 0, 0.18); @@ -3690,7 +3693,7 @@ body.site-guide-page .site-guide-card h3 { } body.site-guide-page .site-guide-card h3 a { - color: var(--dark-yellow); + color: var(--color-brand-dark); font-weight: 800; text-decoration: none; } @@ -3852,7 +3855,7 @@ body.minister-page .minister-hero-lead { } body.minister-page .minister-hero-lead .mark_b { - color: var(--light-yellow); + color: var(--color-brand-light); } body.minister-page .variety-block .intro-text { @@ -3888,8 +3891,8 @@ body.minister-page .minister-hashtag, font-size: clamp(0.78rem, 1.65vw, 0.9rem); letter-spacing: 0.06em; line-height: 1.2; - color: var(--dark-yellow); - background: linear-gradient(180deg, rgba(255, 253, 247, 0.98) 0%, var(--surface-soft) 100%); + color: var(--color-brand-dark); + background: linear-gradient(180deg, rgba(255, 253, 247, 0.98) 0%, var(--color-surface-soft) 100%); border: 1px solid rgba(255, 204, 0, 0.52); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.88) inset, @@ -3972,12 +3975,4 @@ body.minister-page .minister-photo--dual img { } body.minister-page .minister-back { - text-align: center; - margin: 2rem 0 0; -} - -@media (max-width: 640px) { - body.minister-page .minister-photo--dual { - grid-template-columns: 1fr; - } -} \ No newline at end of file + text- \ No newline at end of file diff --git a/assets/css/tablet.css b/assets/css/tablet.css index 211660b..ccfd403 100644 --- a/assets/css/tablet.css +++ b/assets/css/tablet.css @@ -1,257 +1,257 @@ -/* iPad/平板 RWD — max-width ≤1180px(含 iPad 直/橫與小平板/小筆電) */ - -/* 頂欄漢堡:與 style.css 992 斷點一致,避免本檔 1180 規則把選單列壓回橫排 */ -@media (max-width: 991px) { - - .portal-nav>ul { - flex: none; - flex-wrap: nowrap; - justify-content: flex-start; - align-items: center; - } - - .portal-nav>ul>li>a { - flex-direction: row; - } -} - -@media (max-width: 1180px) { - - html:has(.portal-nav) { - scroll-padding-top: clamp(52px, 12vw, 76px); - } - - nav:not(.portal-nav) { - padding-left: clamp(14px, 2vw + 10px, 32px) !important; - padding-right: clamp(14px, 2vw + 10px, 32px) !important; - } - - .portal-nav { - padding-left: clamp(14px, 2vw + 10px, 32px) !important; - padding-right: clamp(14px, 2vw + 10px, 32px) !important; - row-gap: 12px; - flex-wrap: wrap; - align-items: center; - } - - .portal-nav>ul { - align-items: center; - } - - .portal-nav .logo { - width: min(240px, 38vw); - max-width: 100%; - flex-shrink: 0; - } - - .portal-nav>ul { - flex-wrap: wrap; - gap: clamp(12px, 2vw, 18px); - justify-content: flex-end; - min-width: 0; - flex: 1 1 280px; - } - - .portal-nav>ul>li>a { - min-height: 44px; - display: inline-flex; - flex-direction: column; - align-items: center; - justify-content: center; - } - - nav:not(.portal-nav):not(.bilivideo-episode-nav) ul { - gap: clamp(12px, 2vw, 20px); - } - - header.inner-page-header { - background-size: cover; - background-position: center center; - } - - header#origin .hero .site-header-inner .main-title { - font-size: clamp(1.75rem, 2.25vw + 1rem, 2.35rem); - } - - .hero p { - font-size: clamp(1rem, 1.5vw + 0.65rem, 1.15rem); - } - - .container, - .content-container { - padding-left: clamp(14px, 1.5vw + 10px, 22px); - padding-right: clamp(14px, 1.5vw + 10px, 22px); - } - - .home-page .container { - padding-left: clamp(14px, 1.5vw + 10px, 22px); - padding-right: clamp(14px, 1.5vw + 10px, 22px); - } - - section { - padding: clamp(26px, 3vw + 18px, 36px) clamp(16px, 2.5vw + 12px, 28px) !important; - } - - .story-grid { - gap: clamp(18px, 4vw, 28px); - grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); - } - - .card { - padding: clamp(18px, 4vw, 26px); - } - - table { - font-size: 0.92rem; - } - - table th, - table td { - padding: clamp(10px, 2vw, 14px); - } - - /* 首頁/跨時空軌跡:鑽石主軸在平板改左側縱線(對齊舊 ≤900px 邏輯) */ - .merged-storyline::before { - left: 18px; - transform: none; - } - - .merged-storyline .story-node { - width: calc(100% - 44px); - margin-left: 44px; - margin-right: 0; - } - - .merged-storyline .story-node:nth-of-type(odd), - .merged-storyline .story-node:nth-of-type(even) { - margin-left: 44px; - margin-right: 0; - } - - .merged-storyline .story-node::before { - left: -39px; - right: auto; - } - - .merged-storyline .story-node::after, - .merged-storyline .story-node:nth-of-type(odd)::after, - .merged-storyline .story-node:nth-of-type(even)::after { - left: 12px; - right: auto; - top: -14px; - transform: rotate(-8deg); - transform-origin: center center; - display: inline-flex; - align-items: center; - justify-content: center; - line-height: 1.2; - padding: 4px 9px; - } - - .merged-storyline .story-node:nth-of-type(odd)::before, - .merged-storyline .story-node:nth-of-type(even)::before { - left: -39px; - right: auto; - } - - .merged-storyline .story-node:nth-of-type(odd), - .merged-storyline .story-node:nth-of-type(even) { - margin-top: 60px; - } - - /* 紀實長卷/pillar 段落 */ - .chronicle-reader, - .chronicle-pager { - max-width: min(920px, 100%); - } - - .variety-block { - padding: clamp(18px, 4vw, 22px); - } - - .site-header-inner .main-title { - letter-spacing: clamp(3px, 1vw, 6px); - } - - .map-layout { - grid-template-columns: minmax(280px, 42%) minmax(0, 1fr); - gap: clamp(16px, 3vw, 22px); - } - - .map-my-maps-frame { - height: min(52vh, 520px); - min-height: 360px; - } - - .map-embed-all { - gap: 12px; - } - - /* 重逢區兩張演唱會大卡之間留白 */ - #stage-now { - gap: clamp(36px, 5vw, 50px); - } - - /* 演唱會卡片內距 */ - .con-1, - .con-2, - .con-3, - .con-4, - #yellownote-stage { - padding: clamp(32px, 5vw, 44px) clamp(22px, 5vw, 48px) !important; - } - - .title { - margin: clamp(24px, 5vw, 40px) !important; - font-size: clamp(1.15rem, 2.8vw, 1.45rem); - } - - .concert-container { - padding-left: clamp(12px, 3vw, 20px); - padding-right: clamp(12px, 3vw, 20px); - } - - .search-input:focus { - max-width: 100%; - } - - .concert-page .search-input:focus { - width: min(100%, 440px); - } - - .concert-page img[src*="assets/images/concert/"] { - width: min(560px, 88%); - max-width: 100%; - } - - /* 歌詞頁 */ - body.lyrics-page { - margin: clamp(24px, 5vw, 56px) !important; - box-sizing: border-box; - overflow-x: hidden; - } - - html:has(body.lyrics-page) { - font-size: 118.75% !important; - } - - body.lyrics-page .lyrics-main-table { - border-spacing: clamp(12px, 3vw, 24px) !important; - max-width: 100%; - } - - body.lyrics-page .main-left { - width: 100% !important; - display: block; - box-sizing: border-box; - } - - body.lyrics-page .lyrics-main-table p { - font-size: 1.2rem !important; - max-width: none; - } - - body.lyrics-page h1 { - font-size: clamp(1.6rem, 5vw, 2.1rem) !important; - } -} +/* iPad/平板 RWD — max-width ≤1180px(含 iPad 直/橫與小平板/小筆電) */ + +/* 頂欄漢堡:與 style.css 992 斷點一致,避免本檔 1180 規則把選單列壓回橫排 */ +@media (max-width: 991px) { + + .portal-nav>ul { + flex: none; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: center; + } + + .portal-nav>ul>li>a { + flex-direction: row; + } +} + +@media (max-width: 1180px) { + + html:has(.portal-nav) { + scroll-padding-top: clamp(52px, 12vw, 76px); + } + + nav:not(.portal-nav) { + padding-left: clamp(14px, 2vw + 10px, 32px) !important; + padding-right: clamp(14px, 2vw + 10px, 32px) !important; + } + + .portal-nav { + padding-left: clamp(14px, 2vw + 10px, 32px) !important; + padding-right: clamp(14px, 2vw + 10px, 32px) !important; + row-gap: 12px; + flex-wrap: wrap; + align-items: center; + } + + .portal-nav>ul { + align-items: center; + } + + .portal-nav .logo { + width: min(240px, 38vw); + max-width: 100%; + flex-shrink: 0; + } + + .portal-nav>ul { + flex-wrap: wrap; + gap: clamp(12px, 2vw, 18px); + justify-content: flex-end; + min-width: 0; + flex: 1 1 280px; + } + + .portal-nav>ul>li>a { + min-height: 44px; + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + nav:not(.portal-nav):not(.bilivideo-episode-nav) ul { + gap: clamp(12px, 2vw, 20px); + } + + header.inner-page-header { + background-size: cover; + background-position: center center; + } + + header#origin .hero .site-header-inner .main-title { + font-size: clamp(1.75rem, 2.25vw + 1rem, 2.35rem); + } + + .hero p { + font-size: clamp(1rem, 1.5vw + 0.65rem, 1.15rem); + } + + .container, + .content-container { + padding-left: clamp(14px, 1.5vw + 10px, 22px); + padding-right: clamp(14px, 1.5vw + 10px, 22px); + } + + .home-page .container { + padding-left: clamp(14px, 1.5vw + 10px, 22px); + padding-right: clamp(14px, 1.5vw + 10px, 22px); + } + + section { + padding: clamp(26px, 3vw + 18px, 36px) clamp(16px, 2.5vw + 12px, 28px) !important; + } + + .story-grid { + gap: clamp(18px, 4vw, 28px); + grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); + } + + .card { + padding: clamp(18px, 4vw, 26px); + } + + table { + font-size: 0.92rem; + } + + table th, + table td { + padding: clamp(10px, 2vw, 14px); + } + + /* 首頁/跨時空軌跡:鑽石主軸在平板改左側縱線(對齊舊 ≤900px 邏輯) */ + .merged-storyline::before { + left: 18px; + transform: none; + } + + .merged-storyline .story-node { + width: calc(100% - 44px); + margin-left: 44px; + margin-right: 0; + } + + .merged-storyline .story-node:nth-of-type(odd), + .merged-storyline .story-node:nth-of-type(even) { + margin-left: 44px; + margin-right: 0; + } + + .merged-storyline .story-node::before { + left: -39px; + right: auto; + } + + .merged-storyline .story-node::after, + .merged-storyline .story-node:nth-of-type(odd)::after, + .merged-storyline .story-node:nth-of-type(even)::after { + left: 12px; + right: auto; + top: -14px; + transform: rotate(-8deg); + transform-origin: center center; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1.2; + padding: 4px 9px; + } + + .merged-storyline .story-node:nth-of-type(odd)::before, + .merged-storyline .story-node:nth-of-type(even)::before { + left: -39px; + right: auto; + } + + .merged-storyline .story-node:nth-of-type(odd), + .merged-storyline .story-node:nth-of-type(even) { + margin-top: 60px; + } + + /* 紀實長卷/pillar 段落 */ + .chronicle-reader, + .chronicle-pager { + max-width: min(920px, 100%); + } + + .variety-block { + padding: clamp(18px, 4vw, 22px); + } + + .site-header-inner .main-title { + letter-spacing: clamp(3px, 1vw, 6px); + } + + .map-layout { + grid-template-columns: minmax(280px, 42%) minmax(0, 1fr); + gap: clamp(16px, 3vw, 22px); + } + + .map-my-maps-frame { + height: min(52vh, 520px); + min-height: 360px; + } + + .map-embed-all { + gap: 12px; + } + + /* 重逢區兩張演唱會大卡之間留白 */ + #stage-now { + gap: clamp(36px, 5vw, 50px); + } + + /* 演唱會卡片內距 */ + .con-1, + .con-2, + .con-3, + .con-4, + #yellownote-stage { + padding: clamp(32px, 5vw, 44px) clamp(22px, 5vw, 48px) !important; + } + + .title { + margin: clamp(24px, 5vw, 40px) !important; + font-size: clamp(1.15rem, 2.8vw, 1.45rem); + } + + .concert-container { + padding-left: clamp(12px, 3vw, 20px); + padding-right: clamp(12px, 3vw, 20px); + } + + .search-input:focus { + max-width: 100%; + } + + .concert-page .search-input:focus { + width: min(100%, 440px); + } + + .concert-page img[src*="assets/images/concert/"] { + width: min(560px, 88%); + max-width: 100%; + } + + /* 歌詞頁 */ + body.lyrics-page { + margin: clamp(24px, 5vw, 56px) !important; + box-sizing: border-box; + overflow-x: hidden; + } + + html:has(body.lyrics-page) { + font-size: 118.75% !important; + } + + body.lyrics-page .lyrics-main-table { + border-spacing: clamp(12px, 3vw, 24px) !important; + max-width: 100%; + } + + body.lyrics-page .main-left { + width: 100% !important; + display: block; + box-sizing: border-box; + } + + body.lyrics-page .lyrics-main-table p { + font-size: 1.2rem !important; + max-width: none; + } + + body.lyrics-page h1 { + font-size: clamp(1.6rem, 5vw, 2.1rem) !important; + } +} diff --git a/assets/images/230515113027.svg b/assets/images/230515113027.svg index 975adc5..8ee905e 100644 --- a/assets/images/230515113027.svg +++ b/assets/images/230515113027.svg @@ -1,524 +1,524 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/fan-journey-wave-underline.svg b/assets/images/fan-journey-wave-underline.svg index 663c349..98333f2 100644 --- a/assets/images/fan-journey-wave-underline.svg +++ b/assets/images/fan-journey-wave-underline.svg @@ -1,6 +1,6 @@ - + diff --git a/assets/images/icon/balloon.svg b/assets/images/icon/balloon.svg index 63df33c..1046437 100644 --- a/assets/images/icon/balloon.svg +++ b/assets/images/icon/balloon.svg @@ -1,47 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/logov.svg b/assets/images/logov.svg index 9387927..adc45e3 100644 --- a/assets/images/logov.svg +++ b/assets/images/logov.svg @@ -1,1643 +1,1643 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/js/map.js b/assets/js/map.js index 6a17553..718cec4 100644 --- a/assets/js/map.js +++ b/assets/js/map.js @@ -1,304 +1,304 @@ -(() => { - 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 mapEmbedSingle = document.getElementById("map-embed-single"); - const mapEmbedAll = document.getElementById("map-embed-all"); - const openMapLink = document.getElementById("open-map-link"); - const openMapLinksDual = document.getElementById("open-map-links-dual"); - const openMapLinkKo = document.getElementById("open-map-link-ko"); - const openMapLinkEun = document.getElementById("open-map-link-eun"); - const dayGroups = new Map(); - - let currentMember = "eun"; - 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 = { eun: 0, ko: 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 setDualMapVisible(isAll) { - if (mapEmbedSingle && mapEmbedAll) { - mapEmbedSingle.hidden = isAll ? true : false; - mapEmbedAll.hidden = isAll ? false : true; - mapEmbedAll.setAttribute("aria-hidden", isAll ? "false" : "true"); - } - if (openMapLink && openMapLinksDual) { - openMapLink.hidden = isAll ? true : false; - openMapLinksDual.hidden = isAll ? false : true; - } - } - - function updateMapByMember(member) { - const normalized = normalizeMember(member); - if (normalized === "all") { - setDualMapVisible(true); - if (openMapLinkKo) openMapLinkKo.href = memberMaps.ko.open; - if (openMapLinkEun) openMapLinkEun.href = memberMaps.eun.open; - return; - } - setDualMapVisible(false); - const mapConfig = memberMaps[normalized]; - if (!mapConfig || !memberMapFrame) return; - memberMapFrame.src = mapConfig.embed; - if (openMapLink) 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 = "" + dayLabel + ""; - - const body = document.createElement("div"); - body.className = "day-cards"; - body.style.display = "none"; - - group.appendChild(toggle); - group.appendChild(body); - itineraryList.appendChild(group); - 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); - } - const mapKey = currentMember === "all" ? "all" : currentMember; - updateMapByMember(mapKey); - - 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 { - updateMapByMember(currentMember === "all" ? "all" : 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(); -})(); +(() => { + 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 mapEmbedSingle = document.getElementById("map-embed-single"); + const mapEmbedAll = document.getElementById("map-embed-all"); + const openMapLink = document.getElementById("open-map-link"); + const openMapLinksDual = document.getElementById("open-map-links-dual"); + const openMapLinkKo = document.getElementById("open-map-link-ko"); + const openMapLinkEun = document.getElementById("open-map-link-eun"); + const dayGroups = new Map(); + + let currentMember = "eun"; + 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 = { eun: 0, ko: 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 setDualMapVisible(isAll) { + if (mapEmbedSingle && mapEmbedAll) { + mapEmbedSingle.hidden = isAll ? true : false; + mapEmbedAll.hidden = isAll ? false : true; + mapEmbedAll.setAttribute("aria-hidden", isAll ? "false" : "true"); + } + if (openMapLink && openMapLinksDual) { + openMapLink.hidden = isAll ? true : false; + openMapLinksDual.hidden = isAll ? false : true; + } + } + + function updateMapByMember(member) { + const normalized = normalizeMember(member); + if (normalized === "all") { + setDualMapVisible(true); + if (openMapLinkKo) openMapLinkKo.href = memberMaps.ko.open; + if (openMapLinkEun) openMapLinkEun.href = memberMaps.eun.open; + return; + } + setDualMapVisible(false); + const mapConfig = memberMaps[normalized]; + if (!mapConfig || !memberMapFrame) return; + memberMapFrame.src = mapConfig.embed; + if (openMapLink) 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 = "" + dayLabel + ""; + + const body = document.createElement("div"); + body.className = "day-cards"; + body.style.display = "none"; + + group.appendChild(toggle); + group.appendChild(body); + itineraryList.appendChild(group); + 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); + } + const mapKey = currentMember === "all" ? "all" : currentMember; + updateMapByMember(mapKey); + + 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 { + updateMapByMember(currentMember === "all" ? "all" : 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(); +})(); diff --git a/assets/js/particles.js b/assets/js/particles.js index 9638ee1..a4504a0 100644 --- a/assets/js/particles.js +++ b/assets/js/particles.js @@ -1,58 +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(); - }); -})(); +(() => { + 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(); + }); +})(); diff --git a/assets/js/portal-nav.js b/assets/js/portal-nav.js index a1ecb50..0000775 100644 --- a/assets/js/portal-nav.js +++ b/assets/js/portal-nav.js @@ -1,479 +1,479 @@ -(() => { - /** - * ── 導覽「尚未開放」連結 ───────────────────────────────────────── - * 【兩個世界】① 僅 `extra/site-guide.html`:`