站主成長軸 萬年曆 練習室
This commit is contained in:
+127
-122
@@ -499,41 +499,41 @@
|
||||
color: var(--practice-text-dark);
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-status--soon {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: var(--practice-text-muted);
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.45rem;
|
||||
min-height: 42px;
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
border: 1px solid var(--practice-accent);
|
||||
border-radius: 999px;
|
||||
color: var(--practice-text-dark);
|
||||
text-decoration: none;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-link:hover {
|
||||
background: var(--practice-accent-soft);
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-empty {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px dashed var(--practice-border);
|
||||
border-radius: 14px;
|
||||
color: var(--practice-text-muted);
|
||||
background: var(--practice-surface);
|
||||
text-align: center;
|
||||
}
|
||||
body.practice-room-page .practice-room__song-status--soon {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
color: var(--practice-text-muted);
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.45rem;
|
||||
min-height: 42px;
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
border: 1px solid var(--practice-accent);
|
||||
border-radius: 999px;
|
||||
color: var(--practice-text-dark);
|
||||
text-decoration: none;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-link:hover {
|
||||
background: var(--practice-accent-soft);
|
||||
}
|
||||
|
||||
body.practice-room-page .practice-room__song-empty {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px dashed var(--practice-border);
|
||||
border-radius: 14px;
|
||||
color: var(--practice-text-muted);
|
||||
background: var(--practice-surface);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ── 段落練習 ── */
|
||||
body.practice-room-page .practice-room__section-panel {
|
||||
@@ -670,11 +670,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991.98px) {
|
||||
body.practice-room-page .practice-room__song-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 991.98px) {
|
||||
body.practice-room-page .practice-room__song-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -700,7 +700,7 @@
|
||||
<h2 class="practice-room__hero-title" id="practice-hero-title">水晶練習室</h2>
|
||||
<p class="practice-room__hero-en">Crystal Practice Room</p>
|
||||
<p class="practice-room__hero-lead">
|
||||
水晶練習室延續我們當年以<span class="mark_b mark_y">水晶熱舞社、水晶歌詞社與水晶嘻哈社</span>等名稱交流的玩心,將歌曲、舞蹈、歌詞、Rap 與應援整理成可以反覆練習的粉絲向互動工具。第一版先以舞蹈影片練習與歌詞段落整理為主,未來可擴充唱歌、Rap、應援詞、錄音回放與練習紀錄。
|
||||
水晶練習室延續我們當年以<span class="mark_b mark_y">水晶熱舞社、水晶歌詞社與水晶嘻哈社</span>等名稱交流的玩心,將歌曲、舞蹈、歌詞、Rap 與應援整理成可以反覆練習的粉絲向互動工具。第一版先以舞蹈影片練習與歌詞段落整理為主,未來可擴充唱歌、Rap、應援詞、錄音回放與練習紀錄。
|
||||
</p>
|
||||
<div class="practice-room__tag-row">
|
||||
<span class="practice-room__tag"><i class="fa-solid fa-fire" aria-hidden="true"></i> 水晶熱舞社</span>
|
||||
@@ -815,14 +815,14 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ④ 練舞清單 -->
|
||||
<section class="practice-room__block" aria-labelledby="songs-title">
|
||||
<h2 class="practice-room__block-title" id="songs-title">練舞清單</h2>
|
||||
<span class="practice-room__block-sub">DANCE PRACTICE LIST</span>
|
||||
<div class="practice-room__song-grid" data-dance-practice-list aria-live="polite">
|
||||
<p class="practice-room__song-empty">正在載入練舞清單…</p>
|
||||
</div>
|
||||
</section>
|
||||
<!-- ④ 練舞清單 -->
|
||||
<section class="practice-room__block" aria-labelledby="songs-title">
|
||||
<h2 class="practice-room__block-title" id="songs-title">練舞清單</h2>
|
||||
<span class="practice-room__block-sub">DANCE PRACTICE LIST</span>
|
||||
<div class="practice-room__song-grid" data-dance-practice-list aria-live="polite">
|
||||
<p class="practice-room__song-empty">正在載入練舞清單…</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ⑤ 歌詞段落示意 -->
|
||||
<section class="practice-room__block" aria-labelledby="sections-title">
|
||||
@@ -1128,79 +1128,84 @@
|
||||
}
|
||||
});
|
||||
|
||||
updatePlaceholder();
|
||||
updateProgress();
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var list = document.querySelector('[data-dance-practice-list]');
|
||||
if (!list) return;
|
||||
|
||||
function element(tagName, className, text) {
|
||||
var node = document.createElement(tagName);
|
||||
if (className) node.className = className;
|
||||
if (typeof text === 'string') node.textContent = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
function renderEmpty(message) {
|
||||
list.replaceChildren(element('p', 'practice-room__song-empty', message));
|
||||
}
|
||||
|
||||
function renderItems(items) {
|
||||
if (!items.length) {
|
||||
renderEmpty('練舞清單目前整理中。');
|
||||
return;
|
||||
}
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
items.forEach(function (item) {
|
||||
var cardClass = 'practice-room__song-card' + (item.featured ? ' practice-room__song-card--featured' : '');
|
||||
var card = element('article', cardClass);
|
||||
card.appendChild(element('h3', 'practice-room__song-title', item.title));
|
||||
|
||||
var meta = element('div', 'practice-room__song-meta');
|
||||
(item.tags || []).forEach(function (tag) {
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', tag));
|
||||
});
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', '難度:' + item.difficulty));
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', item.progress));
|
||||
card.appendChild(meta);
|
||||
|
||||
var focus = element('p', 'practice-room__song-focus');
|
||||
focus.appendChild(element('strong', '', '練習重點:'));
|
||||
focus.appendChild(document.createTextNode(item.practiceFocus));
|
||||
card.appendChild(focus);
|
||||
|
||||
if (item.videoUrl) {
|
||||
var link = element('a', 'practice-room__song-link', '打開參考影片');
|
||||
link.href = item.videoUrl;
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener noreferrer';
|
||||
card.appendChild(link);
|
||||
}
|
||||
|
||||
var statusClass = 'practice-room__song-status' + (item.comingSoon ? ' practice-room__song-status--soon' : '');
|
||||
card.appendChild(element('span', statusClass, item.note || item.progress));
|
||||
fragment.appendChild(card);
|
||||
});
|
||||
list.replaceChildren(fragment);
|
||||
}
|
||||
|
||||
fetch('dance-practices-data.php', { headers: { Accept: 'application/json' } })
|
||||
.then(function (response) {
|
||||
if (!response.ok) throw new Error('request failed');
|
||||
return response.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!data.ok || !Array.isArray(data.items)) throw new Error('invalid data');
|
||||
renderItems(data.items);
|
||||
})
|
||||
.catch(function () {
|
||||
renderEmpty('練舞清單暫時無法載入,請稍後再試。');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
updatePlaceholder();
|
||||
updateProgress();
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var list = document.querySelector('[data-dance-practice-list]');
|
||||
if (!list) return;
|
||||
|
||||
function element(tagName, className, text) {
|
||||
var node = document.createElement(tagName);
|
||||
if (className) node.className = className;
|
||||
if (typeof text === 'string') node.textContent = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
function renderEmpty(message) {
|
||||
list.replaceChildren(element('p', 'practice-room__song-empty', message));
|
||||
}
|
||||
|
||||
function renderItems(items) {
|
||||
if (!items.length) {
|
||||
renderEmpty('練舞清單目前整理中。');
|
||||
return;
|
||||
}
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
items.forEach(function (item) {
|
||||
var cardClass = 'practice-room__song-card' + (item.featured ? ' practice-room__song-card--featured' : '');
|
||||
var card = element('article', cardClass);
|
||||
card.appendChild(element('h3', 'practice-room__song-title', item.title));
|
||||
|
||||
var meta = element('div', 'practice-room__song-meta');
|
||||
(item.tags || []).forEach(function (tag) {
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', tag));
|
||||
});
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', '難度:' + item.difficulty));
|
||||
meta.appendChild(element('span', 'practice-room__song-tag', item.progress));
|
||||
card.appendChild(meta);
|
||||
|
||||
var focus = element('p', 'practice-room__song-focus');
|
||||
focus.appendChild(element('strong', '', '練習重點:'));
|
||||
focus.appendChild(document.createTextNode(item.practiceFocus));
|
||||
card.appendChild(focus);
|
||||
|
||||
if (item.videoUrl) {
|
||||
var link = element('a', 'practice-room__song-link', '打開參考影片');
|
||||
link.href = item.videoUrl;
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener noreferrer';
|
||||
card.appendChild(link);
|
||||
}
|
||||
|
||||
var statusClass = 'practice-room__song-status' + (item.comingSoon ? ' practice-room__song-status--soon' : '');
|
||||
card.appendChild(element('span', statusClass, item.note || item.progress));
|
||||
fragment.appendChild(card);
|
||||
});
|
||||
list.replaceChildren(fragment);
|
||||
}
|
||||
|
||||
/* 靜態資料,不依賴 PHP:本站部署在 GitHub Pages(不支援 PHP 執行),
|
||||
本機 Live Server 同樣不會執行 .php,所以清單資料直接寫在這裡。
|
||||
完整版(含後台管理、MySQL)在獨立專案 sechskies_fans。 */
|
||||
var danceItems = [
|
||||
{
|
||||
title: 'SECHSKIES 回歸編舞練習影片',
|
||||
tags: ['回歸曲', '編舞練習'],
|
||||
practiceFocus: '跟著示範影片抓基本站位與轉場,作為之後細部拆解動作的參考版本。',
|
||||
videoUrl: 'https://youtu.be/Idvu0XwUrgk?si=v7bD50zRkx90gA42',
|
||||
difficulty: '中等',
|
||||
progress: '整理中',
|
||||
featured: true,
|
||||
comingSoon: false
|
||||
}
|
||||
];
|
||||
|
||||
renderItems(danceItems);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user