chore: variety資料夾改名vedio並同步連結
@@ -39,13 +39,14 @@
|
||||
- **站主索引**(自用):`extra/site-guide.html`(`data-portal-nav-all-open`,不對外)
|
||||
- **內頁 header class**:`inner-page-header`(禁改回舊名)
|
||||
|
||||
### variety/ 頁面
|
||||
### vedio/ 頁面(原 variety/,已改名)
|
||||
|
||||
| 檔案 | 頁面標題 | 說明 |
|
||||
|------|----------|------|
|
||||
| `variety/bangxiao.html` | 世紀級寶藏 / 爆笑養老院 | 甜蜜負擔計量器;六人卡片選取 + jQuery 計算;CTA → `totoga2/ebook.html` |
|
||||
| `variety/variety-shows.html` | 全員發瘋 | 綜藝節目存檔表;tabs + 搜尋;已對齊 albums.html 扁平結構 |
|
||||
| `variety/NJTW/NJTW5.html` | 新西遊記5 | 各自暴走專頁 |
|
||||
| `vedio/bangxiao.html` | 世紀級寶藏 / 爆笑養老院 | 甜蜜負擔計量器;六人卡片選取 + jQuery 計算;CTA → `totoga2/ebook.html` |
|
||||
| `vedio/variety-shows.html` | 全員發瘋 | 綜藝節目存檔表;tabs + 搜尋;已對齊 albums.html 扁平結構 |
|
||||
| `vedio/NJTW/NJTW5.html` | 新西遊記5 | 各自暴走專頁 |
|
||||
| `vedio/vedio-list.html` | 影視清單 | 追劇進度預覽頁(乙級第三題骨架,PHP 後台在 `vedio/vedio-list/`) |
|
||||
|
||||
---
|
||||
|
||||
@@ -57,7 +58,7 @@
|
||||
site-guide 的 depth 數字 = nav 的層級:depth-1 是第一層 `<li>`,depth-2 是子選單項目,depth-3 是 subgroup 裡的巢狀項目。
|
||||
|
||||
2. **`COMING_SOON_PAGES` 只放檔名**(不含路徑)。
|
||||
`normalizePageKey` 只取 href 最後一段,所以 `variety/bangxiao.html` → 比對 `bangxiao.html`。
|
||||
`normalizePageKey` 只取 href 最後一段,所以 `vedio/bangxiao.html` → 比對 `bangxiao.html`。
|
||||
|
||||
3. **直接連結不需要 subgroup**。
|
||||
子選單內只要 `<li><a>` 就夠;`portal-nav__subgroup` 只在該項目還有巢狀子項目時才用(例如「傳奇的轉折」有時間軸、電子書等四項)。
|
||||
@@ -72,7 +73,7 @@
|
||||
|
||||
<!-- 每次對話結束後更新這個區塊 -->
|
||||
|
||||
**最後更新:** 2026-08-04
|
||||
**最後更新:** 2026-08-13
|
||||
|
||||
**進行中:**
|
||||
- 無
|
||||
@@ -89,13 +90,14 @@
|
||||
|
||||
**已完成:**
|
||||
- 建立 AGENTS.md 跨裝置上下文檔案
|
||||
- 新增 `variety/bangxiao.html`(世紀級寶藏 / 爆笑養老院,甜蜜負擔計量器)
|
||||
- `variety/variety-shows.html` 重構:移除多層包裝,對齊 albums.html 扁平結構
|
||||
- 新增 `vedio/bangxiao.html`(世紀級寶藏 / 爆笑養老院,甜蜜負擔計量器)
|
||||
- `vedio/variety-shows.html` 重構:移除多層包裝,對齊 albums.html 扁平結構
|
||||
- portal-nav 新增世紀級寶藏,正確放入淪陷瞬間子選單
|
||||
- `extra/site-guide.html` 同步更新:全員發瘋 → 世紀級寶藏
|
||||
- 新增 `admin/` 推廣部後臺第一階段:登入、控制台、管理者帳號、通用 CRUD、媒體上傳及公開狀態總覽
|
||||
- 水晶熱舞社/水晶練習室/偶像練習生已於 2026-08-04 拆成獨立專案 `sechskies_fans`(另一個 repo,路徑 `d:\Developer\projects\sechskies_fans`,不在本站範圍):30TH 應援報名表單、練舞清單、後台 CRUD 與管理者登入都已搬走並改用自己的資料庫;`extra/site-guide.html` 與本站 `admin/bootstrap.php`/`admin/database/schema.sql` 已同步移除相關項目
|
||||
- `portal-nav.js` 頂欄新增第 7 項「水晶練習室」(Yellow Note 之後),連到獨立專案 sechskies_fans;`extra/site-guide.html` 同步新增對應項目;目前是 coming-soon 佔位,尚未接上真實網址
|
||||
- `variety/` 資料夾整個改名為 `vedio/`,同步修正 portal-nav.js、site-guide.html、style.css 註解、docs/site-structure.md、portal-nav-rules.md 等連結
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -39,13 +39,14 @@
|
||||
- **站主索引**(自用):`extra/site-guide.html`(`data-portal-nav-all-open`,不對外)
|
||||
- **內頁 header class**:`inner-page-header`(禁改回舊名)
|
||||
|
||||
### variety/ 頁面
|
||||
### vedio/ 頁面(原 variety/,已改名)
|
||||
|
||||
| 檔案 | 頁面標題 | 說明 |
|
||||
|------|----------|------|
|
||||
| `variety/bangxiao.html` | 世紀級寶藏 / 爆笑養老院 | 甜蜜負擔計量器;六人卡片選取 + jQuery 計算;CTA → `totoga2/ebook.html` |
|
||||
| `variety/variety-shows.html` | 全員發瘋 | 綜藝節目存檔表;tabs + 搜尋;已對齊 albums.html 扁平結構 |
|
||||
| `variety/NJTW/NJTW5.html` | 新西遊記5 | 各自暴走專頁 |
|
||||
| `vedio/bangxiao.html` | 世紀級寶藏 / 爆笑養老院 | 甜蜜負擔計量器;六人卡片選取 + jQuery 計算;CTA → `totoga2/ebook.html` |
|
||||
| `vedio/variety-shows.html` | 全員發瘋 | 綜藝節目存檔表;tabs + 搜尋;已對齊 albums.html 扁平結構 |
|
||||
| `vedio/NJTW/NJTW5.html` | 新西遊記5 | 各自暴走專頁 |
|
||||
| `vedio/vedio-list.html` | 影視清單 | 追劇進度預覽頁(乙級第三題骨架,PHP 後台在 `vedio/vedio-list/`) |
|
||||
|
||||
---
|
||||
|
||||
@@ -57,7 +58,7 @@
|
||||
site-guide 的 depth 數字 = nav 的層級:depth-1 是第一層 `<li>`,depth-2 是子選單項目,depth-3 是 subgroup 裡的巢狀項目。
|
||||
|
||||
2. **`COMING_SOON_PAGES` 只放檔名**(不含路徑)。
|
||||
`normalizePageKey` 只取 href 最後一段,所以 `variety/bangxiao.html` → 比對 `bangxiao.html`。
|
||||
`normalizePageKey` 只取 href 最後一段,所以 `vedio/bangxiao.html` → 比對 `bangxiao.html`。
|
||||
|
||||
3. **直接連結不需要 subgroup**。
|
||||
子選單內只要 `<li><a>` 就夠;`portal-nav__subgroup` 只在該項目還有巢狀子項目時才用(例如「傳奇的轉折」有時間軸、電子書等四項)。
|
||||
@@ -72,7 +73,7 @@
|
||||
|
||||
<!-- 每次對話結束後更新這個區塊 -->
|
||||
|
||||
**最後更新:** 2026-06-17
|
||||
**最後更新:** 2026-08-13
|
||||
|
||||
**進行中:**
|
||||
- 無
|
||||
@@ -82,10 +83,11 @@
|
||||
|
||||
**已完成:**
|
||||
- 建立 CLAUDE.md 跨裝置上下文檔案
|
||||
- 新增 `variety/bangxiao.html`(世紀級寶藏 / 爆笑養老院,甜蜜負擔計量器)
|
||||
- `variety/variety-shows.html` 重構:移除多層包裝,對齊 albums.html 扁平結構
|
||||
- 新增 `vedio/bangxiao.html`(世紀級寶藏 / 爆笑養老院,甜蜜負擔計量器)
|
||||
- `vedio/variety-shows.html` 重構:移除多層包裝,對齊 albums.html 扁平結構
|
||||
- portal-nav 新增世紀級寶藏,正確放入淪陷瞬間子選單
|
||||
- `extra/site-guide.html` 同步更新:全員發瘋 → 世紀級寶藏
|
||||
- `variety/` 資料夾整個改名為 `vedio/`,同步修正 portal-nav.js、site-guide.html、style.css 註解、docs/site-structure.md、portal-nav-rules.md 等連結
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2695,7 +2695,7 @@ header.inner-page-header .sub-title {
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
|
||||
/* variety/NJTW/NJTW5.html — 樣式改為同資料夾 njtw5.css,避免與全站 style 雙重定義 */
|
||||
/* vedio/NJTW/NJTW5.html — 樣式改為同資料夾 njtw5.css,避免與全站 style 雙重定義 */
|
||||
|
||||
/* Chronicle (webcomic-like reader) */
|
||||
.chronicle-controls {
|
||||
|
||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 202 KiB |
|
After Width: | Height: | Size: 215 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 126 KiB |
@@ -259,7 +259,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a target="_blank" rel="noopener noreferrer" href="${rp}variety/bangxiao.html"><span class="portal-nav__label">世紀級寶藏</span></a></li>
|
||||
<li><a target="_blank" rel="noopener noreferrer" href="${rp}vedio/bangxiao.html"><span class="portal-nav__label">世紀級寶藏</span></a></li>
|
||||
<li><a target="_blank" rel="noopener noreferrer" href="${rp}member/member.html"><span class="portal-nav__label">完整的六顆</span></a></li>
|
||||
<li><a target="_blank" rel="noopener noreferrer" href="${rp}concert/concert.html"><span class="portal-nav__label">現場的震撼</span></a>
|
||||
<ul class="portal-submenu">
|
||||
|
||||
@@ -20,7 +20,7 @@ alwaysApply: true
|
||||
|
||||
1. **未經站主逐句同意**:不得從 `COMING_SOON_PAGES` **刪**檔名、不得擴充 `INDEX_NAV_OPEN_HASHES`、不得在 `buildPortalNavInnerHTML` **新增**可點項、不得把籌備中改成真 `href`、不得刪站主已同意列入頂欄的項。
|
||||
2. **「檔案在 repo」≠「可開放導覽」**;不得自行推論。
|
||||
3. **`totoga2/readable.html`(圖文好讀版,檔名 `readable.html`)**、**`variety/variety.html`**:站主**沒有明講對外開放**時,檔名**必須**留在 `COMING_SOON_PAGES`(訪客頂欄不可點進)。要開放時**只**能等站主說了再從 Set 移除。
|
||||
3. **`totoga2/readable.html`(圖文好讀版,檔名 `readable.html`)**、**`vedio/variety.html`**:站主**沒有明講對外開放**時,檔名**必須**留在 `COMING_SOON_PAGES`(訪客頂欄不可點進)。要開放時**只**能等站主說了再從 Set 移除。
|
||||
4. **「刪除/拿掉/不要了」**:若未寫明是**單一檔案**、**頂欄某一列**、**整段子選單**還是**整個資料夾**,**一律先問站主**,禁止自行擴大刪除範圍。
|
||||
5. **不確定**是否開放、連哪、是否例外:**先問站主再改**,不要猜。
|
||||
6. 站主說刪 **`某頁#錨點`**:見下方 **§8 頁面錨點刪除**(先改 DOM,再修死鏈;禁止只動導覽)。
|
||||
@@ -32,7 +32,7 @@ alwaysApply: true
|
||||
在 **`buildPortalNavInnerHTML`**(`assets/js/portal-nav.js`)裡維護連結:
|
||||
|
||||
- 依資訊架構放在對應的 **`<li>`** 底下;需要子選單時用 **`portal-submenu`**。
|
||||
- `href` 使用**站根相對路徑**(腳本會依當前頁深度加上前綴 `rp`):例如 `` `${rp}variety/variety.html` ``、`` `${rp}index.html#section` ``。
|
||||
- `href` 使用**站根相對路徑**(腳本會依當前頁深度加上前綴 `rp`):例如 `` `${rp}vedio/variety.html` ``、`` `${rp}index.html#section` ``。
|
||||
- Logo 列:`` `${rp}index.html` `` 與 `` `${rp}assets/images/logov.svg` ``。
|
||||
|
||||
新增或調整完後,所有帶 **`data-portal-nav`** 的 `<nav class="portal-nav">` 都會在載入腳本時被注入同一份 HTML。
|
||||
@@ -93,7 +93,7 @@ alwaysApply: true
|
||||
<script src="assets/js/portal-nav.js"></script>
|
||||
```
|
||||
|
||||
內頁(例如 `extra/`、`fallen/`、`member/`、`yellow-note/`、`variety/` 下)請用相對站根深度,例如:
|
||||
內頁(例如 `extra/`、`fallen/`、`member/`、`yellow-note/`、`vedio/` 下)請用相對站根深度,例如:
|
||||
|
||||
```html
|
||||
<script src="../assets/js/portal-nav.js"></script>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|----------------|------------------|
|
||||
| 淪陷瞬間 · 初心與軌跡 | `index.html` |
|
||||
| 傳奇的轉折 | `fallen/totoga2.html` |
|
||||
| 全員發瘋 · 隊長帶弟弟 | `variety/variety.html`(錨點 `#variety`) |
|
||||
| 全員發瘋 · 各自暴走 · 新西遊記 | `variety/NJTW/NJTW5.html` |
|
||||
| 全員發瘋 · 隊長帶弟弟 | `vedio/variety.html`(錨點 `#variety`) |
|
||||
| 全員發瘋 · 各自暴走 · 新西遊記 | `vedio/NJTW/NJTW5.html` |
|
||||
| 完整的六顆 | `member/member.html` |
|
||||
| 現場的震撼 | `concert/concert.html` |
|
||||
| 黃色留聲機 | `albums/albums.html` |
|
||||
@@ -21,7 +21,7 @@
|
||||
- `member/` — 成員介紹(六顆水晶)
|
||||
- `concert/`、`albums/` — 與選單同名主題
|
||||
- `yellow-note/` — Yellow Note(minister + map)
|
||||
- `variety/` — 綜藝與 NJTW 子頁
|
||||
- `vedio/` — 綜藝與 NJTW 子頁
|
||||
- `extra/` — 未掛主欄之草稿、複本、全站索引 `site-guide.html` 等
|
||||
- `assets/` — 共用靜態資源
|
||||
- `docs/sql/` — SQL 練習、計畫(`sql_plan.md`)與 `.sql` 腳本/匯出
|
||||
|
||||
@@ -80,18 +80,18 @@
|
||||
<span class="sg-node sg-node--extra">首頁區塊錨點:<code>#start</code>·<code>#mission</code>·<code>#timeline</code>(<code>#story</code> 未開放)</span>
|
||||
</li>
|
||||
<li data-site-guide-depth="2">
|
||||
<span class="sg-node"><a href="../variety/bangxiao.html">世紀級寶藏</a></span>
|
||||
<span class="sg-node"><a href="../vedio/bangxiao.html">世紀級寶藏</a></span>
|
||||
<ul>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra">頁內「爆笑養老院」甜蜜負擔計量器區塊(同頁,非另一個檔案)</span></li>
|
||||
<li data-site-guide-depth="3">
|
||||
<span class="sg-node sg-node--extra">variety/ 其他相關頁(不在頂欄)</span>
|
||||
<span class="sg-node sg-node--extra">vedio/ 其他相關頁(不在頂欄)</span>
|
||||
<ul>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../variety/variety.html#variety">綜藝主頁・隊長帶弟弟</a></span></li>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../variety/variety-shows.html">節目存檔表</a></span></li>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../vedio/variety.html#variety">綜藝主頁・隊長帶弟弟</a></span></li>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../vedio/variety-shows.html">節目存檔表</a></span></li>
|
||||
<li data-site-guide-depth="4">
|
||||
<span class="sg-node sg-node--extra sg-node--nolink">各自暴走</span>
|
||||
<ul>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../variety/NJTW/NJTW5.html">新西遊記</a></span></li>
|
||||
<li data-site-guide-depth="4"><span class="sg-node sg-node--extra"><a href="../vedio/NJTW/NJTW5.html">新西遊記</a></span></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -168,8 +168,8 @@
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra"><a href="../s20260612_04_jq_calculator.html">s20260612_04_jq_calculator.html(學校作業)</a></span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra"><a href="../sechskies_brand_color_spec.html">sechskies_brand_color_spec.html(品牌色規範)</a></span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra"><a href="../totoga2/readable_ebookcontent.html">totoga2/readable_ebookcontent.html(電子書內容草稿)</a></span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra"><a href="../variety/vedio-list.html">variety/vedio-list.html(深夜清單,追劇進度預覽頁)</a></span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra" title="admin/api/back 等 PHP 後台,非靜態站主線">variety/vedio-list/(追劇清單後台練習,非本站主線)</span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra"><a href="../vedio/vedio-list.html">vedio/vedio-list.html(深夜清單,追劇進度預覽頁)</a></span></li>
|
||||
<li data-site-guide-depth="3"><span class="sg-node sg-node--extra" title="admin/api/back 等 PHP 後台,非靜態站主線">vedio/vedio-list/(追劇清單後台練習,非本站主線)</span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li data-site-guide-depth="2">
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>水晶男孩|瘋子與天才</title>
|
||||
<link rel="stylesheet" href="../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="../assets/css/tablet.css">
|
||||
</head>
|
||||
|
||||
<body class="chronicle-page">
|
||||
<header class="inner-page-header">
|
||||
<div class="header-inner site-header-inner">
|
||||
<h1 class="main-title">瘋子與天才</h1>
|
||||
<div class="subtitle-wrap">
|
||||
<span class="sub-title">EUN JI-WON × VARIETY GRAVITY</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="portal-nav" aria-label="水晶男孩推廣部導覽" data-portal-nav></nav>
|
||||
|
||||
<canvas id="particles"></canvas>
|
||||
|
||||
<main class="content-container variety-page-main chronicle-reader">
|
||||
<section id="variety" class="variety-block">
|
||||
<h2 class="section-title">瘋狂出演中</h2>
|
||||
<p class="intro-text">鏡頭一開就跑偏、台詞唸不完,卻總能把段子的節奏剪成「非他不可」——這是最容易被路人一眼看見的瘋勁,也是綜藝剪輯願意一路卡特寫給他的理由。</p>
|
||||
<p class="intro-text">卸妝後的聊天、運動場上的暴走、對成員毫不修飾的吐槽;那些看起來像日常,其實比劇本更誇張。</p>
|
||||
<p class="intro-text"><a href="variety-shows.html#variety-shows">全員發瘋</a>:團綜「隊長帶弟弟」與個綜「各自暴走」分表整理;名場面與入坑路線仍會陸續補在本區。</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>SECHSKIES Fanpage © 2026 - 黃色氣球永遠飄揚</p>
|
||||
<a href="https://jekkinoopy.github.io/Portfolio/" class="studio-link" target="_blank">
|
||||
Design by <span class="mark_b">Jekkinoopy Studio</span>
|
||||
</a>
|
||||
</footer>
|
||||
|
||||
<script src="../assets/js/portal-nav.js"></script>
|
||||
<script src="../assets/js/particles.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 460 KiB After Width: | Height: | Size: 460 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 954 KiB After Width: | Height: | Size: 954 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 550 KiB After Width: | Height: | Size: 550 KiB |
@@ -62,7 +62,7 @@ body.njtw5-page header.main-header {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* 圖檔與此 CSS 同資料夾(variety/NJTW/) */
|
||||
/* 圖檔與此 CSS 同資料夾(vedio/NJTW/) */
|
||||
background-color: #1a1812;
|
||||
background-image: url("1538075001_cu.jpg");
|
||||
background-size: cover;
|
||||
|
Before Width: | Height: | Size: 968 KiB After Width: | Height: | Size: 968 KiB |
@@ -4,13 +4,13 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>水晶男孩|追劇清單</title>
|
||||
<title>水晶男孩|影視清單</title>
|
||||
<link rel="stylesheet" href="../assets/css/style.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="../assets/css/tablet.css">
|
||||
<style>
|
||||
/* ── 追劇清單頁面專用樣式 ── */
|
||||
/* ── 影視清單頁面專用樣式 ── */
|
||||
|
||||
.vedio-list-page .vedio-intro {
|
||||
text-align: left;
|
||||
@@ -114,6 +114,19 @@
|
||||
text-align: center;
|
||||
padding: 0.75rem;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vedio-list-page .drama-card__poster--image {
|
||||
padding: 0;
|
||||
background: var(--color-surface-soft);
|
||||
}
|
||||
|
||||
.vedio-list-page .drama-card__poster--image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vedio-list-page .drama-card__meta {
|
||||
@@ -320,7 +333,7 @@
|
||||
<body class="vedio-list-page">
|
||||
<header class="inner-page-header">
|
||||
<div class="header-inner site-header-inner">
|
||||
<h1 class="main-title">深夜清單</h1>
|
||||
<h1 class="main-title">影視清單</h1>
|
||||
<div class="subtitle-wrap">
|
||||
<span class="sub-title">DRAMA & VARIETY WATCH LIST</span>
|
||||
</div>
|
||||
@@ -335,38 +348,33 @@
|
||||
|
||||
<section class="vedio-intro">
|
||||
<h2 class="section-title">正在追的那些夜晚</h2>
|
||||
<p>
|
||||
有些夜晚適合考古黃色奇蹟,有些夜晚則是——螢幕一亮,人就栽進另一個世界。
|
||||
綜藝裡的失控笑聲、戲劇裡的心跳停拍,都值得被好好記下來:看到哪一季、哪一集、哪一句台詞剛把你釘在沙發上。
|
||||
<p>綜藝裡的失控笑聲、戲劇裡的心跳停拍,都值得被好好記下來:看到哪一季、哪一集、哪一句台詞剛把你釘在沙發上。
|
||||
</p>
|
||||
<p>
|
||||
這裡先收兩部最近在追的:一部是把人丟進肯亞還能笑到缺氧的<span class="mark_y">韓綜</span>,
|
||||
一部是把 1997 年的青春寫得又甜又疼的<span class="mark_b">韓劇</span>。
|
||||
點進去,進度與入口都在;先別急著一次追完,慢慢養也很好看。
|
||||
</p>
|
||||
<p>
|
||||
<!-- <p>
|
||||
此頁為線上靜態預覽。完整資料庫與後台 CRUD(乙級第三題骨架)請本機 XAMPP 匯入
|
||||
<code>variety/vedio-list/dramas.sql</code> 後,開啟
|
||||
<a href="vedio-list/"><code>variety/vedio-list/</code></a>。
|
||||
</p>
|
||||
<code>vedio/vedio-list/dramas.sql</code> 後,開啟
|
||||
<a href="vedio-list/"><code>vedio/vedio-list/</code></a>。
|
||||
</p> -->
|
||||
</section>
|
||||
|
||||
<section class="list-section" aria-labelledby="vedio-list-heading">
|
||||
<h2 class="section-title" id="vedio-list-heading">追劇清單</h2>
|
||||
<p class="list-lead">先用類型找——綜藝還是戲劇,跟 OTT 首頁那排分類一樣直覺。</p>
|
||||
<h2 class="section-title" id="vedio-list-heading">影視清單</h2>
|
||||
<!-- <p class="list-lead">先用類型找——綜藝還是戲劇,跟 OTT 首頁那排分類一樣直覺。</p> -->
|
||||
|
||||
<div class="type-tabs" role="tablist" aria-label="作品類型">
|
||||
<button type="button" class="type-tab is-active" role="tab" aria-selected="true"
|
||||
data-type="all">全部</button>
|
||||
<button type="button" class="type-tab" role="tab" aria-selected="false"
|
||||
data-type="variety">綜藝</button>
|
||||
<button type="button" class="type-tab" role="tab" aria-selected="false"
|
||||
data-type="drama">戲劇</button>
|
||||
<button type="button" class="type-tab" role="tab" aria-selected="false" data-type="variety">綜藝</button>
|
||||
<button type="button" class="type-tab" role="tab" aria-selected="false" data-type="drama">戲劇</button>
|
||||
</div>
|
||||
|
||||
<div class="drama-grid" id="dramaGrid">
|
||||
<article class="drama-card" data-type="variety" data-id="kenya" tabindex="0"
|
||||
aria-label="三傻遊肯亞,綜藝">
|
||||
<article class="drama-card" data-type="variety" data-id="kenya" tabindex="0" aria-label="三傻遊肯亞,綜藝">
|
||||
<div class="drama-card__poster" aria-hidden="true">NETFLIX · 綜藝</div>
|
||||
<div class="drama-card__meta">
|
||||
<span class="drama-tag">綜藝</span>
|
||||
@@ -376,16 +384,17 @@
|
||||
<p class="drama-card__progress">觀看進度:第 1 季・第 2 集・看到 28:40</p>
|
||||
<p class="drama-card__note">三人剛被扔進野外,表情比獅子還慌。</p>
|
||||
<div class="drama-card__actions">
|
||||
<a class="is-primary" href="https://www.netflix.com/title/82031207"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
onclick="event.stopPropagation()">繼續觀看</a>
|
||||
<a class="is-primary" href="https://www.netflix.com/tw/title/82031207" target="_blank"
|
||||
rel="noopener noreferrer" onclick="event.stopPropagation()">繼續觀看</a>
|
||||
<button type="button" data-open-detail="kenya">查看詳情</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="drama-card" data-type="drama" data-id="reply1997" tabindex="0"
|
||||
aria-label="請回答1997,戲劇">
|
||||
<div class="drama-card__poster" aria-hidden="true">DISNEY+ · 戲劇</div>
|
||||
<article class="drama-card" data-type="drama" data-id="reply1997" tabindex="0" aria-label="請回答1997,戲劇">
|
||||
<!-- 海報來源:Wikipedia,版權歸原著作權人所有 -->
|
||||
<div class="drama-card__poster drama-card__poster--image" aria-hidden="true">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/zh/a/a9/Reply_1997.jpg" alt="" loading="lazy">
|
||||
</div>
|
||||
<div class="drama-card__meta">
|
||||
<span class="drama-tag">戲劇</span>
|
||||
<span class="drama-tag drama-tag--platform">Disney+</span>
|
||||
@@ -394,9 +403,9 @@
|
||||
<p class="drama-card__progress">觀看進度:第 1 季・第 5 集・看到 41:12</p>
|
||||
<p class="drama-card__note">宿舍夜談剛結束,收音機還在響,心卻已經開始亂。</p>
|
||||
<div class="drama-card__actions">
|
||||
<a class="is-primary" href="https://www.disneyplus.com/en-tw/browse/entity-3979fb82-8681-44e8-b7be-e313091f0d73"
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
onclick="event.stopPropagation()">繼續觀看</a>
|
||||
<a class="is-primary"
|
||||
href="https://www.disneyplus.com/en-tw/browse/entity-3979fb82-8681-44e8-b7be-e313091f0d73"
|
||||
target="_blank" rel="noopener noreferrer" onclick="event.stopPropagation()">繼續觀看</a>
|
||||
<button type="button" data-open-detail="reply1997">查看詳情</button>
|
||||
</div>
|
||||
</article>
|
||||
@@ -438,8 +447,8 @@
|
||||
intro: '三個人、一座肯亞,以及無數個「這也能出事?」的現場。笑點來得又急又野,像把旅行節目的安全感整袋拆掉,只留下腎上腺素與默契。',
|
||||
progress: '第 1 季|第 2 集|28:40',
|
||||
note: '三人剛被扔進野外,表情比獅子還慌。',
|
||||
extra: '狀態:追劇中 · 開始看的那天:最近才入坑,進度還很乖。',
|
||||
watchUrl: 'https://www.netflix.com/title/82031207'
|
||||
extra: '狀態:影視中 · 開始看的那天:最近才入坑,進度還很乖。',
|
||||
watchUrl: 'https://www.netflix.com/tw/title/82031207'
|
||||
},
|
||||
reply1997: {
|
||||
typeLabel: '戲劇|Disney+',
|
||||
@@ -447,7 +456,7 @@
|
||||
intro: '把 1997 寫進宿舍、收音機與那一聲來不及說出口的喜歡。甜的時候甜到發亮,疼的時候又老實得讓人不敢快轉——那種青春,看完會想立刻打電話給誰。',
|
||||
progress: '第 1 季|第 5 集|41:12',
|
||||
note: '宿舍夜談剛結束,收音機還在響,心卻已經開始亂。',
|
||||
extra: '狀態:追劇中 · 提醒自己:下一集容易哭,衛生紙先備好。',
|
||||
extra: '狀態:影視中 · 提醒自己:下一集容易哭,衛生紙先備好。',
|
||||
watchUrl: 'https://www.disneyplus.com/en-tw/browse/entity-3979fb82-8681-44e8-b7be-e313091f0d73'
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
# 打歌舞台後台|乙級練習版
|
||||
|
||||
1. 開啟 XAMPP Control Panel,啟動 Apache 與 MySQL。
|
||||
2. 進入 phpMyAdmin,匯入 `setup.sql`。
|
||||
3. 將本資料夾放入 `C:\xampp\htdocs\`,或在此資料夾執行:
|
||||
`C:\xampp\php\php.exe -S 127.0.0.1:8080`
|
||||
4. 開啟 `http://127.0.0.1:8080/login.php`。
|
||||
5. 練習帳號:`admin`;密碼:`1234`。
|
||||
|
||||
練習內容:Session 登入、PDO、CRUD、預備敘述、防 XSS、CSRF、列表排序、顯示/隱藏與 JSON API。
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php';
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$rows = $pdo->query('SELECT stage_date,youtube_id,station,program,title,note,sort_order FROM stages WHERE is_visible=1 ORDER BY sort_order,stage_date,id')->fetchAll();
|
||||
echo json_encode(['stages'=>$rows], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
session_start();
|
||||
|
||||
const DB_HOST = '127.0.0.1';
|
||||
const DB_NAME = 'three_words_10th';
|
||||
const DB_USER = 'root';
|
||||
const DB_PASS = '';
|
||||
|
||||
try {
|
||||
$pdo = new PDO(
|
||||
'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
|
||||
DB_USER,
|
||||
DB_PASS,
|
||||
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
|
||||
);
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
exit('資料庫連線失敗,請先啟動 XAMPP MySQL 並匯入 setup.sql。');
|
||||
}
|
||||
|
||||
function e(?string $value): string { return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8'); }
|
||||
function loggedIn(): bool { return isset($_SESSION['admin_id']); }
|
||||
function requireLogin(): void { if (!loggedIn()) { header('Location: login.php'); exit; } }
|
||||
function csrf(): string {
|
||||
if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(24));
|
||||
return $_SESSION['csrf'];
|
||||
}
|
||||
function checkCsrf(): void {
|
||||
if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) exit('表單驗證失敗');
|
||||
}
|
||||
function youtubeId(string $url): string {
|
||||
if (preg_match('~(?:youtu\.be/|youtube\.com/(?:watch\?v=|embed/|shorts/))([\w-]{11})~', $url, $m)) return $m[1];
|
||||
return preg_match('/^[\w-]{11}$/', $url) ? $url : '';
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php'; requireLogin(); checkCsrf();
|
||||
$stmt = $pdo->prepare('DELETE FROM stages WHERE id = ?');
|
||||
$stmt->execute([(int)($_POST['id'] ?? 0)]);
|
||||
header('Location: index.php');
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php';
|
||||
requireLogin();
|
||||
$edit = ['id'=>'','stage_date'=>'','youtube_id'=>'','station'=>'','program'=>'','title'=>'','note'=>'','sort_order'=>0,'is_visible'=>1];
|
||||
if (isset($_GET['edit'])) {
|
||||
$stmt = $pdo->prepare('SELECT * FROM stages WHERE id = ?'); $stmt->execute([(int)$_GET['edit']]);
|
||||
$edit = $stmt->fetch() ?: $edit;
|
||||
}
|
||||
$stages = $pdo->query('SELECT * FROM stages ORDER BY sort_order ASC, stage_date ASC, id ASC')->fetchAll();
|
||||
?>
|
||||
<!doctype html><html lang="zh-Hant"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>打歌舞台後台</title><link rel="stylesheet" href="style.css"></head><body>
|
||||
<header><div><p class="eyebrow">THREE WORDS · 10TH</p><h1>打歌舞台後台</h1></div><nav><a href="stages.php" target="_blank">查看前台 ↗</a><a href="api.php" target="_blank">JSON API ↗</a><a href="logout.php">登出</a></nav></header>
|
||||
<main class="adminGrid">
|
||||
<section class="panel formPanel"><div class="panelTitle"><span>01</span><h2><?=$edit['id']?'修改舞台':'新增舞台'?></h2></div>
|
||||
<form method="post" action="save.php"><input type="hidden" name="csrf" value="<?=csrf()?>"><input type="hidden" name="id" value="<?=e((string)$edit['id'])?>">
|
||||
<div class="two"><label>播出日期<input type="date" name="stage_date" required value="<?=e($edit['stage_date'])?>"></label><label>顯示順序<input type="number" name="sort_order" value="<?=e((string)$edit['sort_order'])?>"></label></div>
|
||||
<label>YouTube 網址或影片 ID<input name="youtube_url" required placeholder="https://www.youtube.com/watch?v=..." value="<?=e($edit['youtube_id'])?>"></label>
|
||||
<div class="two"><label>電視台<input name="station" required placeholder="SBS" value="<?=e($edit['station'])?>"></label><label>節目名稱<input name="program" required placeholder="人氣歌謠" value="<?=e($edit['program'])?>"></label></div>
|
||||
<label>舞台標題<input name="title" required value="<?=e($edit['title'])?>"></label><label>備註<textarea name="note" rows="3"><?=e($edit['note'])?></textarea></label>
|
||||
<label class="check"><input type="checkbox" name="is_visible" value="1" <?=$edit['is_visible']?'checked':''?>> 前台顯示</label><div class="formActions"><button><?=$edit['id']?'儲存修改':'新增資料'?></button><?php if($edit['id']):?><a href="index.php">取消修改</a><?php endif;?></div></form></section>
|
||||
<section class="panel listPanel"><div class="panelTitle"><span>02</span><h2>資料列表</h2><b><?=count($stages)?> 筆</b></div>
|
||||
<div class="tableWrap"><table><thead><tr><th>順序</th><th>日期/縮圖</th><th>電視台/舞台</th><th>狀態</th><th>操作</th></tr></thead><tbody>
|
||||
<?php foreach($stages as $row):?><tr><td><?=e((string)$row['sort_order'])?></td><td><time><?=e($row['stage_date'])?></time><img src="https://i.ytimg.com/vi/<?=e($row['youtube_id'])?>/mqdefault.jpg" alt="影片縮圖"></td><td><strong><?=e($row['station'])?> · <?=e($row['program'])?></strong><span><?=e($row['title'])?></span></td><td><i class="status <?=$row['is_visible']?'on':''?>"><?=$row['is_visible']?'顯示':'隱藏'?></i></td><td class="ops"><a href="?edit=<?=$row['id']?>">修改</a><form method="post" action="delete.php" onsubmit="return confirm('確定刪除這筆資料?')"><input type="hidden" name="csrf" value="<?=csrf()?>"><input type="hidden" name="id" value="<?=$row['id']?>"><button>刪除</button></form></td></tr><?php endforeach; ?>
|
||||
</tbody></table></div></section></main></body></html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php';
|
||||
if (loggedIn()) { header('Location: index.php'); exit; }
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
checkCsrf();
|
||||
$stmt = $pdo->prepare('SELECT * FROM admins WHERE account = ? AND password = SHA2(?, 256)');
|
||||
$stmt->execute([trim($_POST['account'] ?? ''), $_POST['password'] ?? '']);
|
||||
if ($admin = $stmt->fetch()) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['admin_id'] = $admin['id'];
|
||||
$_SESSION['admin_account'] = $admin['account'];
|
||||
header('Location: index.php'); exit;
|
||||
}
|
||||
$error = '帳號或密碼錯誤';
|
||||
}
|
||||
?>
|
||||
<!doctype html><html lang="zh-Hant"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>後台登入</title><link rel="stylesheet" href="style.css"></head>
|
||||
<body class="loginPage"><main class="loginCard"><p class="eyebrow">THREE WORDS · ADMIN</p><h1>舞台資料管理</h1><p>乙級練習:Session 登入與資料庫驗證</p><?php if ($error): ?><div class="alert"><?=e($error)?></div><?php endif; ?>
|
||||
<form method="post"><input type="hidden" name="csrf" value="<?=csrf()?>"><label>帳號<input name="account" required autofocus value="admin"></label><label>密碼<input type="password" name="password" required value="1234"></label><button>登入後台</button></form></main></body></html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php';
|
||||
$_SESSION = [];
|
||||
session_destroy();
|
||||
header('Location: login.php');
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php'; requireLogin(); checkCsrf();
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$youtube = youtubeId(trim($_POST['youtube_url'] ?? ''));
|
||||
if (!$youtube) exit('YouTube 網址或 ID 格式錯誤');
|
||||
$data = [$_POST['stage_date'] ?? '', $youtube, trim($_POST['station'] ?? ''), trim($_POST['program'] ?? ''), trim($_POST['title'] ?? ''), trim($_POST['note'] ?? ''), (int)($_POST['sort_order'] ?? 0), isset($_POST['is_visible']) ? 1 : 0];
|
||||
if ($id) {
|
||||
$stmt = $pdo->prepare('UPDATE stages SET stage_date=?,youtube_id=?,station=?,program=?,title=?,note=?,sort_order=?,is_visible=? WHERE id=?');
|
||||
$data[] = $id; $stmt->execute($data);
|
||||
} else {
|
||||
$stmt = $pdo->prepare('INSERT INTO stages(stage_date,youtube_id,station,program,title,note,sort_order,is_visible) VALUES(?,?,?,?,?,?,?,?)');
|
||||
$stmt->execute($data);
|
||||
}
|
||||
header('Location: index.php');
|
||||
@@ -0,0 +1,27 @@
|
||||
CREATE DATABASE IF NOT EXISTS three_words_10th CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE three_words_10th;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admins (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
account VARCHAR(50) NOT NULL UNIQUE,
|
||||
password CHAR(64) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stages (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
stage_date DATE NOT NULL,
|
||||
youtube_id VARCHAR(11) NOT NULL,
|
||||
station VARCHAR(30) NOT NULL,
|
||||
program VARCHAR(100) NOT NULL,
|
||||
title VARCHAR(150) NOT NULL,
|
||||
note VARCHAR(255) NOT NULL DEFAULT '',
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
is_visible TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT IGNORE INTO admins (account, password) VALUES ('admin', SHA2('1234', 256));
|
||||
INSERT INTO stages (stage_date, youtube_id, station, program, title, note, sort_order)
|
||||
SELECT '2016-12-04', '8HTqr3Wp-R0', 'SBS', '인기가요 · Inkigayo', 'THREE WORDS · Goodbye Stage', '十週年收藏舞台', 10
|
||||
WHERE NOT EXISTS (SELECT 1 FROM stages WHERE youtube_id = '8HTqr3Wp-R0');
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php require __DIR__ . '/config.php'; $stages=$pdo->query('SELECT * FROM stages WHERE is_visible=1 ORDER BY sort_order,stage_date,id')->fetchAll(); ?>
|
||||
<!doctype html><html lang="zh-Hant"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>THREE WORDS 打歌舞台</title><link rel="stylesheet" href="style.css"></head><body class="front"><main><p class="eyebrow">MUSIC SHOW ARCHIVE</p><h1>打歌舞台</h1><div class="frontTable"><div class="frontHead"><span>DATE</span><span>VIDEO</span><span>STATION</span></div><?php foreach($stages as $s):?><article><time><?=e($s['stage_date'])?></time><a href="https://youtu.be/<?=e($s['youtube_id'])?>" target="_blank"><img src="https://i.ytimg.com/vi/<?=e($s['youtube_id'])?>/hqdefault.jpg" alt="<?=e($s['title'])?>"><div><strong><?=e($s['title'])?></strong><small>WATCH ↗</small></div></a><div class="tv"><strong><?=e($s['station'])?></strong><span><?=e($s['program'])?></span></div></article><?php endforeach;?></div><a class="back" href="index.php">回後台</a></main></body></html>
|
||||
@@ -0,0 +1,2 @@
|
||||
:root{--ink:#07101d;--cream:#f2ede2;--gold:#efb53f;--blue:#16334d;--muted:#69727d}*{box-sizing:border-box}body{margin:0;background:#e8e2d6;color:var(--ink);font-family:Arial,"Microsoft JhengHei",sans-serif}a{color:inherit}.eyebrow{font:700 10px Arial;letter-spacing:.3em;color:#8a6c19}header{display:flex;justify-content:space-between;align-items:end;padding:32px 4vw;background:var(--ink);color:var(--cream)}h1{margin:8px 0 0;font:900 clamp(35px,5vw,68px)/1 serif}header nav{display:flex;gap:18px;flex-wrap:wrap}header nav a{text-decoration:none;border-bottom:1px solid var(--gold);padding-bottom:4px}.adminGrid{display:grid;grid-template-columns:minmax(310px,.7fr) minmax(600px,1.6fr);gap:24px;padding:28px 4vw}.panel{background:var(--cream);padding:25px;box-shadow:0 15px 45px rgba(7,16,29,.08)}.panelTitle{display:flex;align-items:center;gap:13px;margin-bottom:24px;border-bottom:1px solid #aaa;padding-bottom:15px}.panelTitle span{display:grid;place-content:center;width:35px;height:35px;border-radius:50%;background:var(--gold);font-weight:900}.panelTitle h2{margin:0;font:800 28px serif}.panelTitle b{margin-left:auto;color:var(--muted)}label{display:grid;gap:8px;margin:0 0 17px;font-size:13px;font-weight:700}input,textarea{width:100%;border:1px solid #aaa;background:#fffdf7;padding:11px;font:inherit}.two{display:grid;grid-template-columns:1fr 1fr;gap:14px}.check{display:flex;align-items:center}.check input{width:auto}.formActions{display:flex;align-items:center;gap:15px}.formActions button,.loginCard button{border:0;background:var(--gold);padding:13px 20px;font-weight:900;cursor:pointer}.tableWrap{overflow:auto}table{width:100%;border-collapse:collapse;min-width:760px}th,td{text-align:left;border-bottom:1px solid #aaa;padding:12px 10px;vertical-align:middle}th{font:700 9px Arial;letter-spacing:.15em;color:#76682f}td img{display:block;width:130px;aspect-ratio:16/9;object-fit:cover;margin-top:8px}td strong,td span{display:block}td span{margin-top:7px;color:var(--muted);font-size:13px}.status{display:inline-block;padding:5px 8px;background:#bbb;font-style:normal;font-size:12px}.status.on{background:var(--gold)}.ops{display:flex;gap:9px;align-items:center}.ops form{margin:0}.ops button{border:0;background:transparent;color:#9b2f22;text-decoration:underline;cursor:pointer}.loginPage{min-height:100vh;display:grid;place-content:center;background:radial-gradient(circle at 80% 10%,#3f5c72,var(--ink) 55%)}.loginCard{width:min(440px,90vw);padding:38px;background:var(--cream);box-shadow:0 30px 90px #0006}.loginCard h1{font-size:48px}.alert{padding:10px;background:#ffd9d2;color:#922;margin:15px 0}.front{background:var(--cream)}.front main{padding:80px 8vw}.front h1{font-size:90px}.frontTable{border-top:2px solid var(--ink);margin-top:50px}.frontHead,.frontTable article{display:grid;grid-template-columns:.55fr 2fr .8fr;gap:25px;align-items:center}.frontHead{padding:12px 0;border-bottom:1px solid #aaa;font:700 9px Arial;letter-spacing:.2em}.frontTable article{padding:22px 0;border-bottom:1px solid #aaa}.frontTable time{font:900 30px Arial}.frontTable article>a{display:grid;grid-template-columns:220px 1fr;gap:20px;align-items:center;text-decoration:none}.frontTable img{width:100%;aspect-ratio:16/9;object-fit:cover}.frontTable small{display:block;margin-top:10px;color:#8a6c19}.tv strong{display:block;font:900 48px Arial;color:#c48f17}.tv span{font-size:12px}.back{display:inline-block;margin-top:30px}.frontTable article>a:hover img{filter:brightness(.75)}
|
||||
@media(max-width:900px){.adminGrid{grid-template-columns:1fr}.frontHead{display:none}.frontTable article{grid-template-columns:1fr}.frontTable article>a{grid-template-columns:1fr}.front h1{font-size:60px}}@media(max-width:560px){header{align-items:start;flex-direction:column;gap:22px}.adminGrid{padding:18px}.two{grid-template-columns:1fr}.front main{padding:55px 6vw}}
|
||||
@@ -0,0 +1,20 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root{--ink:#07101d;--cream:#f2ede2;--gold:#efb53f;--blue:#16334d;--line:rgba(255,255,255,.22)}
|
||||
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--ink);color:var(--cream);font-family:Arial,"Noto Sans TC","Microsoft JhengHei",sans-serif}button,a{font:inherit}
|
||||
.hero{position:relative;min-height:100svh;overflow:hidden;background:radial-gradient(circle at 76% 18%,#80583c 0,#243f57 18%,#0a1726 49%,#050b13 100%);transition:1s}.hero.isLit{background:radial-gradient(circle at 73% 23%,#ffc676 0,#355e7c 25%,#0b1d31 54%,#050b13 100%)}
|
||||
nav{position:absolute;z-index:6;top:0;left:0;right:0;display:flex;justify-content:space-between;align-items:center;padding:26px 4vw;border-bottom:1px solid var(--line);font:700 10px Arial;letter-spacing:.28em}.logo{font-size:24px;letter-spacing:-.08em}.logo span{margin-left:7px;color:var(--gold);font-size:12px;vertical-align:top}
|
||||
.light{position:absolute;width:46vw;height:46vw;right:-4vw;top:-12vw;border-radius:50%;background:rgba(255,194,111,.16);filter:blur(30px);transition:1s}.isLit .light{background:rgba(255,202,115,.38);transform:scale(1.15)}
|
||||
.frames{position:absolute;inset:12vh 5vw 8vh 42vw;perspective:900px}.frames i{position:absolute;display:block;width:36%;height:72%;border:1px solid rgba(255,255,255,.42);background:linear-gradient(135deg,rgba(255,255,255,.06),transparent);backdrop-filter:blur(2px);transform:rotateY(-14deg) rotateZ(4deg);box-shadow:0 30px 80px rgba(0,0,0,.24)}.frames i:nth-child(1){left:0;top:12%}.frames i:nth-child(2){left:29%;top:2%}.frames i:nth-child(3){left:58%;top:15%}
|
||||
.noise{position:absolute;inset:0;opacity:.14;pointer-events:none;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 160 160' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E")}
|
||||
.heroText{position:relative;z-index:4;padding:16vh 0 11vh 7vw;width:min(760px,90vw)}.kicker,.sectionTag{font:700 10px/1.5 Arial;letter-spacing:.34em;color:var(--gold)}h1{margin:28px 0 12px;font:900 clamp(76px,12vw,178px)/.72 Arial;letter-spacing:-.09em}h1 span{display:block}.outline{color:transparent;-webkit-text-stroke:1.5px rgba(242,237,226,.75)}
|
||||
.anniversary{display:flex;align-items:center;gap:16px;margin:24px 0}.anniversary strong{font:900 clamp(72px,9vw,132px)/.7 Arial;color:var(--gold);letter-spacing:-.08em}.anniversary p{font:700 16px/1.15 Arial;letter-spacing:.12em}.dates{font:700 12px Arial;letter-spacing:.2em}.dates b{color:var(--gold);margin:0 10px}.actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:36px}.actions button{padding:15px 20px;border:1px solid transparent;cursor:pointer;transition:.25s}.primary{background:var(--gold);color:var(--ink);font-weight:800}.secondary{background:transparent;color:var(--cream);border-color:rgba(255,255,255,.5)!important}.actions button:hover{transform:translateY(-3px)}.threeDots{position:absolute;z-index:4;right:4vw;bottom:36px;display:flex;gap:10px}.threeDots b{width:8px;height:8px;border:1px solid var(--cream);border-radius:50%}.threeDots b:first-child{background:var(--gold);border-color:var(--gold)}
|
||||
.statement,.words,.memory{padding:100px 8vw}.statement{display:grid;grid-template-columns:1fr 3fr;gap:6vw;background:var(--gold);color:var(--ink)}.statement .sectionTag{color:var(--ink)}.hangul{font:700 13px Arial;letter-spacing:.24em}.statement h2{font:900 clamp(48px,8vw,112px)/1 serif;margin:20px 0 42px;letter-spacing:-.06em}.bigCopy{font:700 clamp(25px,3.4vw,48px)/1.55 serif;margin:0}
|
||||
.words{background:var(--cream);color:var(--ink)}.words .sectionTag{color:#7c682f}.wordGrid{display:grid;grid-template-columns:repeat(3,1fr);margin-top:65px;border-top:1px solid #999}.wordGrid article{padding:28px 32px 45px 0;margin-right:32px;border-right:1px solid #aaa}.wordGrid span{font-size:11px;color:#786d51}.wordGrid h3{font:900 clamp(44px,7vw,100px)/1 Arial;letter-spacing:-.07em;margin:28px 0 16px}.wordGrid p{color:#59606a;line-height:1.7}
|
||||
.lyricsPreview{position:relative;overflow:hidden;display:grid;grid-template-columns:1fr 2fr;gap:7vw;padding:100px 8vw;background:radial-gradient(circle at 8% 15%,#28455f 0,#102337 32%,#07101d 74%);border-top:1px solid rgba(255,255,255,.12)}.lyricsPreview:after{content:"3";position:absolute;right:-.04em;bottom:-.32em;font:900 min(48vw,680px)/1 Arial;color:rgba(255,255,255,.025);pointer-events:none}.lyricsMeta{position:relative;z-index:1}.lyricsMeta>span{display:block;margin-top:38px;font:900 clamp(38px,5vw,72px)/.95 Arial;letter-spacing:-.06em;color:transparent;-webkit-text-stroke:1px rgba(242,237,226,.5)}.lyricsLines{position:relative;z-index:1;border-left:1px solid rgba(239,181,63,.6);padding-left:clamp(25px,4vw,64px)}.lyricsLines p{margin:0 0 18px;font:700 clamp(22px,3vw,44px)/1.25 serif;letter-spacing:-.02em}.lyricsLines p:nth-child(2n){color:#aebdca}.lyricsLines a{display:inline-flex;align-items:center;gap:22px;margin-top:28px;padding:15px 20px;background:var(--gold);color:var(--ink);font-weight:800;text-decoration:none;transition:.25s}.lyricsLines a:hover{transform:translateY(-3px);box-shadow:0 15px 35px rgba(0,0,0,.28)}.lyricsLines a span{font-size:18px}
|
||||
.memory{background:#0c1a2a}.memory>.sectionTag{display:block;margin-bottom:55px}.memory article{display:grid;grid-template-columns:1fr 2fr;gap:6vw;border-top:1px solid var(--line);padding:40px 0}.memory strong{font:900 clamp(42px,7vw,96px)/1 Arial;color:var(--gold);letter-spacing:-.06em}.memory h3{font:700 clamp(25px,3vw,42px)/1.2 serif;margin:0 0 16px}.memory p{max-width:650px;color:#b9c0c8;line-height:1.8;margin:0}
|
||||
.video{padding:90px 8vw;background:#d9d0bf;color:var(--ink);display:grid;grid-template-columns:minmax(250px,.75fr) minmax(0,1.5fr);align-items:center;gap:7vw}.video .sectionTag{color:#796727}.video h2{font:800 clamp(42px,5vw,76px)/1.12 serif;margin:25px 0 32px}.videoHeading>a{display:inline-block;color:var(--ink);font-weight:800;text-decoration:none;border-bottom:1px solid var(--ink);padding-bottom:5px}.videoHeading>a:hover{color:#796727}.videoFrame{position:relative;width:100%;aspect-ratio:16/9;background:#050b13;box-shadow:0 35px 80px rgba(7,16,29,.25);overflow:hidden}.videoFrame:before{content:"";position:absolute;inset:-1px;border:1px solid rgba(255,255,255,.22);pointer-events:none;z-index:1}.videoFrame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
|
||||
.stageArchive{padding:100px 8vw;background:var(--cream);color:var(--ink)}.stageIntro{display:grid;grid-template-columns:1fr 1.5fr;gap:20px 6vw;align-items:end;margin-bottom:55px}.stageIntro .sectionTag{color:#796727;grid-column:1/-1}.stageIntro h2{margin:0;font:900 clamp(54px,8vw,108px)/.9 serif;letter-spacing:-.06em}.stageIntro>p:last-child{max-width:470px;margin:0;color:#59606a;line-height:1.8}.stageTable{border-top:2px solid var(--ink)}.stageHead,.stageRow{display:grid;grid-template-columns:.55fr 2fr .8fr;gap:28px;align-items:center}.stageHead{padding:15px 0;border-bottom:1px solid #9e998e;font:700 9px Arial;letter-spacing:.2em;color:#76682f}.stageRow{padding:24px 0;border-bottom:1px solid #aaa59b}.stageRow time{font:900 clamp(22px,2.5vw,38px)/1 Arial;letter-spacing:-.04em}.stageVideo{display:grid;grid-template-columns:minmax(150px,240px) 1fr;gap:24px;align-items:center;color:var(--ink);text-decoration:none}.stageThumb{position:relative;display:block;aspect-ratio:16/9;overflow:hidden;background:#0a1726}.stageThumb img{width:100%;height:100%;object-fit:cover;transition:.35s}.stageThumb b{position:absolute;inset:50% auto auto 50%;translate:-50% -50%;width:46px;height:46px;border-radius:50%;display:grid;place-content:center;padding-left:3px;background:var(--gold);box-shadow:0 8px 25px rgba(0,0,0,.3)}.stageVideo:hover img{transform:scale(1.05)}.stageVideo>span:last-child{display:grid;gap:12px}.stageVideo strong{font:800 clamp(18px,2vw,28px)/1.25 serif}.stageVideo small{font:700 9px Arial;letter-spacing:.15em;color:#796727}.station{display:grid;gap:8px}.station strong{font:900 clamp(30px,4vw,58px)/1 Arial;color:#c48f17}.station span{font-size:12px;color:#59606a}
|
||||
footer{display:flex;justify-content:space-between;gap:20px;padding:26px 4vw;background:#040910;color:#8d97a4;font:10px Arial;letter-spacing:.16em}
|
||||
@media(max-width:720px){.hero{min-height:820px}.frames{inset:12vh -18vw 29vh 36vw;opacity:.8}.heroText{padding:17vh 7vw 8vh}.heroText h1{font-size:72px}.statement{grid-template-columns:1fr;padding:70px 7vw}.words,.memory{padding:75px 7vw}.wordGrid{grid-template-columns:1fr}.wordGrid article{border-right:0;border-bottom:1px solid #aaa;margin:0}.lyricsPreview{grid-template-columns:1fr;padding:75px 7vw}.lyricsMeta>span{margin:22px 0 36px}.lyricsLines{padding-left:24px}.lyricsLines p{font-size:24px}.memory article{grid-template-columns:1fr}.video{grid-template-columns:1fr;padding:65px 7vw;gap:42px}.video h2{font-size:48px}.stageArchive{padding:75px 7vw}.stageIntro{grid-template-columns:1fr}.stageIntro .sectionTag{grid-column:auto}.stageHead{display:none}.stageRow{grid-template-columns:1fr;gap:18px;padding:28px 0}.stageVideo{grid-template-columns:1fr}.stageRow time{font-size:30px}.station{grid-template-columns:auto 1fr;align-items:baseline}.station strong{font-size:38px}footer{flex-direction:column}}
|
||||
@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "THREE WORDS · 10th Anniversary",
|
||||
description: "SECHSKIES〈세 단어 (THREE WORDS)〉發行十週年紀念頁:2016.10.07—2026.10.07。",
|
||||
icons: { icon: "/favicon.svg" },
|
||||
openGraph: {
|
||||
title: "THREE WORDS · 10th Anniversary",
|
||||
description: "現在、這裡、我們。十年後,再次相遇。",
|
||||
images: [{ url: "/og.png", width: 1536, height: 1024 }],
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
return <html lang="zh-Hant"><body>{children}</body></html>;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
const moments = [
|
||||
{ year: "2016.10.07", title: "重新相遇", text: "睽違十六年後,SECHSKIES 以〈세 단어 (THREE WORDS)〉帶回重逢的聲音。" },
|
||||
{ year: "2026.10.07", title: "十年以後", text: "旋律走過十年,當時的感動仍停在現在、這裡、我們之間。" },
|
||||
];
|
||||
|
||||
const stages = [
|
||||
{
|
||||
date: "2016.12.04",
|
||||
videoId: "8HTqr3Wp-R0",
|
||||
station: "SBS",
|
||||
program: "인기가요 · Inkigayo",
|
||||
note: "THREE WORDS · Goodbye Stage",
|
||||
},
|
||||
];
|
||||
|
||||
export default function Home() {
|
||||
const [lit, setLit] = useState(false);
|
||||
|
||||
function downloadPoster() {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = 1080;
|
||||
canvas.height = 1350;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
const glow = ctx.createRadialGradient(780, 300, 10, 780, 300, 900);
|
||||
glow.addColorStop(0, "#e0a16b");
|
||||
glow.addColorStop(.34, "#264765");
|
||||
glow.addColorStop(1, "#07101d");
|
||||
ctx.fillStyle = glow;
|
||||
ctx.fillRect(0, 0, 1080, 1350);
|
||||
ctx.strokeStyle = "rgba(255,255,255,.45)";
|
||||
ctx.lineWidth = 2;
|
||||
[150, 390, 630].forEach((x, index) => {
|
||||
ctx.strokeRect(x, 180 + index * 70, 420, 660);
|
||||
});
|
||||
ctx.fillStyle = "#f5efe2";
|
||||
ctx.font = "700 106px Arial";
|
||||
ctx.fillText("THREE", 72, 980);
|
||||
ctx.fillText("WORDS", 72, 1085);
|
||||
ctx.fillStyle = "#efb53f";
|
||||
ctx.font = "700 36px Arial";
|
||||
ctx.fillText("10TH ANNIVERSARY", 76, 1155);
|
||||
ctx.fillStyle = "#f5efe2";
|
||||
ctx.font = "30px Arial";
|
||||
ctx.fillText("2016.10.07 — 2026.10.07", 76, 1225);
|
||||
ctx.font = "26px Arial";
|
||||
ctx.fillText("NOW · HERE · US", 76, 1285);
|
||||
const link = document.createElement("a");
|
||||
link.download = "three-words-10th-anniversary.png";
|
||||
link.href = canvas.toDataURL("image/png");
|
||||
link.click();
|
||||
}
|
||||
|
||||
return (
|
||||
<main>
|
||||
<section className={`hero ${lit ? "isLit" : ""}`}>
|
||||
<nav>
|
||||
<span className="logo">3W<span>10</span></span>
|
||||
<span>2016 — 2026</span>
|
||||
</nav>
|
||||
|
||||
<div className="light" aria-hidden="true" />
|
||||
<div className="frames" aria-hidden="true"><i /><i /><i /></div>
|
||||
<div className="noise" aria-hidden="true" />
|
||||
|
||||
<div className="heroText">
|
||||
<p className="kicker">SECHSKIES · 세 단어</p>
|
||||
<h1><span>THREE</span><span className="outline">WORDS</span></h1>
|
||||
<div className="anniversary"><strong>10</strong><p>TH<br />ANNIVERSARY</p></div>
|
||||
<p className="dates">2016.10.07 <b>—</b> 2026.10.07</p>
|
||||
<div className="actions">
|
||||
<button className="primary" onClick={() => setLit(!lit)}>{lit ? "讓記憶停在這裡" : "點亮第十年的光"} <span>✦</span></button>
|
||||
<button className="secondary" onClick={downloadPoster}>下載 IG 紀念圖 ↓</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="threeDots"><b /><b /><b /></div>
|
||||
</section>
|
||||
|
||||
<section className="statement">
|
||||
<p className="sectionTag">01 / TEN YEARS LATER</p>
|
||||
<div>
|
||||
<p className="hangul">지금 · 여기 · 우리</p>
|
||||
<h2>現在。這裡。我們。</h2>
|
||||
<p className="bigCopy">有些歌不只是被聽見,<br />而是替一段等待留下名字。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="words">
|
||||
<p className="sectionTag">02 / THREE WORDS</p>
|
||||
<div className="wordGrid">
|
||||
<article><span>01</span><h3>NOW</h3><p>十年後的此刻,重新按下播放。</p></article>
|
||||
<article><span>02</span><h3>HERE</h3><p>回到那個讓我們再次相遇的地方。</p></article>
|
||||
<article><span>03</span><h3>US</h3><p>歌曲仍在,我們也仍然在這裡。</p></article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="lyricsPreview">
|
||||
<div className="lyricsMeta">
|
||||
<p className="sectionTag">03 / LYRICS PREVIEW</p>
|
||||
<span>세 단어<br />THREE WORDS</span>
|
||||
</div>
|
||||
<div className="lyricsLines">
|
||||
<p>I just wanna be with you</p>
|
||||
<p>내가 사는 이유</p>
|
||||
<p>다시는 멀리 가지 않을게요</p>
|
||||
<p>I'll always be here for you</p>
|
||||
<p>세월이 지난 후</p>
|
||||
<a href="https://jekkinoopy.github.io/sechskies/extra/lyrics.html" target="_blank" rel="noreferrer">完整歌詞與歌曲資料 <span>↗</span></a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="memory">
|
||||
<p className="sectionTag">04 / FROM THEN TO NOW</p>
|
||||
{moments.map((moment) => <article key={moment.year}><strong>{moment.year}</strong><div><h3>{moment.title}</h3><p>{moment.text}</p></div></article>)}
|
||||
</section>
|
||||
|
||||
<section className="video">
|
||||
<div className="videoHeading">
|
||||
<p className="sectionTag">OFFICIAL MUSIC VIDEO</p>
|
||||
<h2>再聽一次,<br />十年前的三個詞。</h2>
|
||||
<a href="https://www.youtube.com/watch?v=m7Zt_p9S-yg" target="_blank" rel="noreferrer">在 YouTube 開啟 ↗</a>
|
||||
</div>
|
||||
<div className="videoFrame">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/m7Zt_p9S-yg?rel=0"
|
||||
title="SECHSKIES - 세 단어 (THREE WORDS) Official Music Video"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
allowFullScreen
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="stageArchive">
|
||||
<div className="stageIntro">
|
||||
<p className="sectionTag">05 / MUSIC SHOW ARCHIVE</p>
|
||||
<h2>打歌舞台</h2>
|
||||
<p>把當年的舞台依日期收好,從十年前重新播放。</p>
|
||||
</div>
|
||||
<div className="stageTable" role="table" aria-label="THREE WORDS 打歌舞台列表">
|
||||
<div className="stageHead" role="row">
|
||||
<span role="columnheader">DATE</span>
|
||||
<span role="columnheader">VIDEO</span>
|
||||
<span role="columnheader">STATION</span>
|
||||
</div>
|
||||
{stages.map((stage) => (
|
||||
<div className="stageRow" role="row" key={stage.videoId}>
|
||||
<time role="cell" dateTime={stage.date}>{stage.date}</time>
|
||||
<a className="stageVideo" role="cell" href={`https://www.youtube.com/watch?v=${stage.videoId}`} target="_blank" rel="noreferrer">
|
||||
<span className="stageThumb">
|
||||
<img src={`https://i.ytimg.com/vi/${stage.videoId}/hqdefault.jpg`} alt={`${stage.program} ${stage.note} 影片縮圖`} />
|
||||
<b>▶</b>
|
||||
</span>
|
||||
<span><strong>{stage.note}</strong><small>WATCH ON YOUTUBE ↗</small></span>
|
||||
</a>
|
||||
<div className="station" role="cell"><strong>{stage.station}</strong><span>{stage.program}</span></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer><span>FAN-MADE 10TH ANNIVERSARY TRIBUTE</span><span>SECHSKIES · THREE WORDS · 2016—2026</span></footer>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.4 MiB |
@@ -0,0 +1,6 @@
|
||||
壓縮包包含:
|
||||
十週年網站原始碼
|
||||
CSS 與分享圖
|
||||
最新的打歌舞台表格
|
||||
PHP/MySQL 乙級練習後台
|
||||
沒有包含 node_modules、建置檔或 Git 資料。D 槽原專案目前未被修改。
|
||||