Merge branch 'main' of https://github.com/jekkinoopy/sechskies
# Conflicts: # yellow-note/crystal-dance-survey.html # yellow-note/practice-room.html
This commit is contained in:
@@ -1,724 +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 href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<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>
|
||||
/* ?? Bootstrap ??敺???靽風嚗? index-bootstrap.html ??嚗?
|
||||
Bootstrap Reboot ?函?璅惜?豢??券?閮?body嚗?憿?畾菔嚗??嚗? ?ㄐ?典?????撖怠 Bootstrap 敺??璅惜?豢??函??蝡??祆?潘?
|
||||
銝?韐? .section-title ?? class ?豢??剁?銝蔣?踵?隞見撘??? */
|
||||
body {
|
||||
background-color: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
font-family: 'Noto Sans TC', 'Microsoft JhengHei', system-ui, sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
dd,
|
||||
blockquote,
|
||||
hr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 瘞湔?梯?蝷橘?瘞湔?瑕酋?典誨?冽?銝?頩??港??? 憿銝敺?朣蝡?color-tokens嚗?-color-brand 蝟餃?嚗?銝?菔??*/
|
||||
:root {
|
||||
--dance-yellow: var(--color-brand);
|
||||
--dance-yellow-light: var(--color-brand-light);
|
||||
--dance-yellow-dark: var(--color-brand-dark);
|
||||
--dance-ink: var(--color-brand-dark);
|
||||
}
|
||||
|
||||
/* 憭扳?摨?嚗???函??蝷曉??閬死嚗??芾????銝??函??梁??header.jpg */
|
||||
body.crystal-dance-page header.inner-page-header {
|
||||
background-image: url('../assets/images/crystal-dance-hero.jpg');
|
||||
background-position: center 68%;
|
||||
}
|
||||
|
||||
/* ?? Hero ?嚗窒??inner-page-header ?嗡蜓璅??ㄐ?芣撘????批?閬踝? ?? */
|
||||
.crystal-dance-hero {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.crystal-dance-hero .category-tag {
|
||||
display: inline-block;
|
||||
background: var(--dance-yellow-light);
|
||||
color: var(--dance-ink);
|
||||
padding: .35rem 1.1rem;
|
||||
border-radius: 999px;
|
||||
font-size: .8rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.crystal-dance-hero .hero-desc {
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.85;
|
||||
max-width: 640px;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
|
||||
.crystal-dance-hero .quick-nav {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
justify-content: center;
|
||||
gap: .6rem;
|
||||
padding: .25rem 0 .5rem;
|
||||
}
|
||||
|
||||
.crystal-dance-hero .quick-nav a {
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* --- ?挾?賢?冽?憿見撘?--- */
|
||||
.section-alt {
|
||||
background: rgba(255, 204, 0, 0.08);
|
||||
}
|
||||
|
||||
.section-kicker {
|
||||
font-weight: 800;
|
||||
color: var(--dance-yellow-dark);
|
||||
letter-spacing: 2px;
|
||||
font-size: .85rem;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.crystal-dance-page .section-title {
|
||||
text-align: left;
|
||||
margin-bottom: 1.1rem;
|
||||
}
|
||||
|
||||
.section-lead {
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.85;
|
||||
max-width: 760px;
|
||||
}
|
||||
|
||||
.section-lead+.section-lead {
|
||||
margin-top: .9rem;
|
||||
}
|
||||
|
||||
/* --- 瘣餃?銝餉?閬?/ 銵典 Banner --- */
|
||||
.event-banner {
|
||||
background: linear-gradient(135deg, var(--dance-yellow) 0%, var(--dance-yellow-light) 100%);
|
||||
border-radius: 24px;
|
||||
padding: 2.25rem 2.5rem;
|
||||
text-align: center;
|
||||
color: var(--dance-ink);
|
||||
box-shadow: 0 12px 30px rgba(255, 204, 0, .25);
|
||||
}
|
||||
|
||||
.event-banner .event-badge {
|
||||
display: inline-block;
|
||||
background: var(--dance-ink);
|
||||
color: var(--dance-yellow-light);
|
||||
padding: .35rem 1.1rem;
|
||||
border-radius: 999px;
|
||||
font-size: .8rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: .9rem;
|
||||
}
|
||||
|
||||
.event-banner h2 {
|
||||
font-weight: 900;
|
||||
letter-spacing: 3px;
|
||||
font-size: 1.9rem;
|
||||
margin-bottom: .6rem;
|
||||
}
|
||||
|
||||
.event-banner p {
|
||||
margin: 0 auto;
|
||||
font-weight: 600;
|
||||
letter-spacing: .5px;
|
||||
max-width: 640px;
|
||||
}
|
||||
|
||||
/* --- ?梯?蝷曆?蝝對??摮?chip --- */
|
||||
.keyword-row {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.keyword-chip {
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--dance-yellow);
|
||||
border-radius: 999px;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 700;
|
||||
color: var(--dance-ink);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .4rem;
|
||||
}
|
||||
|
||||
/* --- 20TH 敶梁??“ --- */
|
||||
.video-card {
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--dance-yellow);
|
||||
border-radius: 16px;
|
||||
padding: 1rem;
|
||||
height: 100%;
|
||||
box-shadow: 0 6px 18px rgba(255, 204, 0, .1);
|
||||
}
|
||||
|
||||
.video-tag {
|
||||
display: inline-block;
|
||||
background: var(--dance-yellow-dark);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: .75rem;
|
||||
padding: .3rem .8rem;
|
||||
border-radius: 999px;
|
||||
margin-bottom: .75rem;
|
||||
}
|
||||
|
||||
.video-card .ratio {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- 蝬?? --- */
|
||||
.song-card {
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--dance-yellow);
|
||||
border-radius: 16px;
|
||||
padding: 1.5rem;
|
||||
height: 100%;
|
||||
box-shadow: 0 6px 18px rgba(255, 204, 0, .1);
|
||||
}
|
||||
|
||||
.song-card h4 {
|
||||
color: var(--dance-yellow-dark);
|
||||
font-weight: 800;
|
||||
margin-bottom: .8rem;
|
||||
}
|
||||
|
||||
.song-card .song-meta {
|
||||
font-size: .78rem;
|
||||
font-weight: 800;
|
||||
color: var(--dance-ink);
|
||||
background: var(--dance-yellow-light);
|
||||
display: inline-block;
|
||||
padding: .15rem .6rem;
|
||||
border-radius: 999px;
|
||||
margin-bottom: .4rem;
|
||||
}
|
||||
|
||||
.song-card p {
|
||||
font-size: .9rem;
|
||||
color: var(--color-text-muted);
|
||||
line-height: 1.7;
|
||||
margin-bottom: .9rem;
|
||||
}
|
||||
|
||||
/* --- 30TH ?隡? --- */
|
||||
.countdown-strip {
|
||||
background: var(--dance-ink);
|
||||
color: var(--dance-yellow-light);
|
||||
border-radius: 16px;
|
||||
padding: .9rem 1.5rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
/* --- 30TH ???銵典 --- */
|
||||
.form-intro {
|
||||
background: var(--color-surface-soft);
|
||||
border-left: 4px solid var(--dance-yellow-dark);
|
||||
padding: 1rem 1.25rem;
|
||||
border-radius: 0 12px 12px 0;
|
||||
color: var(--dance-ink);
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.75rem;
|
||||
}
|
||||
|
||||
.form-panel {
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--dance-yellow);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
height: 100%;
|
||||
box-shadow: 0 8px 24px rgba(255, 204, 0, .12);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-weight: 800;
|
||||
color: var(--dance-yellow-dark);
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-weight: 700;
|
||||
color: var(--dance-ink);
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select {
|
||||
border: 1.5px solid var(--color-brand-light);
|
||||
border-radius: 12px;
|
||||
padding: .65rem .9rem;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
.form-select:focus {
|
||||
border-color: var(--dance-yellow-dark);
|
||||
box-shadow: 0 0 0 .2rem rgba(255, 204, 0, .25);
|
||||
}
|
||||
|
||||
.form-control[type="file"] {
|
||||
border-style: dashed;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* 頨思遢 / ?閎隞交??? radio?heckbox ?嚗??身憭??湔餈?撖虫??? */
|
||||
.btn-outline-dance {
|
||||
border: 1.5px solid var(--dance-yellow-dark);
|
||||
color: var(--dance-yellow-dark);
|
||||
border-radius: 999px;
|
||||
font-weight: 600;
|
||||
padding: .4rem 1.15rem;
|
||||
}
|
||||
|
||||
.btn-check:checked+.btn-outline-dance,
|
||||
.btn-outline-dance:hover {
|
||||
background: var(--dance-yellow);
|
||||
color: var(--dance-ink);
|
||||
border-color: var(--dance-yellow-dark);
|
||||
}
|
||||
|
||||
.btn-dance {
|
||||
background: var(--dance-yellow);
|
||||
color: var(--dance-ink);
|
||||
border: 2px solid var(--dance-yellow-dark);
|
||||
border-radius: 999px;
|
||||
font-weight: 800;
|
||||
padding: .75rem;
|
||||
}
|
||||
|
||||
.btn-dance:hover {
|
||||
background: var(--dance-yellow-dark);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-reset-dance {
|
||||
background: #fff;
|
||||
color: var(--dance-yellow-dark);
|
||||
border: 2px solid var(--dance-yellow-dark);
|
||||
border-radius: 999px;
|
||||
font-weight: 700;
|
||||
padding: .75rem;
|
||||
}
|
||||
|
||||
.btn-reset-dance:hover {
|
||||
background: #fdecec;
|
||||
border-color: #dc3545;
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
/* --- 憛怠神???--- */
|
||||
.info-card {
|
||||
background: linear-gradient(160deg, var(--dance-ink) 0%, var(--color-bg-raised) 100%);
|
||||
color: var(--dance-yellow-light);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
height: 100%;
|
||||
box-shadow: 0 8px 24px rgba(78, 73, 43, .3);
|
||||
}
|
||||
|
||||
.info-tag {
|
||||
display: inline-block;
|
||||
background: var(--dance-yellow);
|
||||
color: var(--dance-ink);
|
||||
padding: .3rem 1rem;
|
||||
border-radius: 999px;
|
||||
font-size: .75rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-card h3 {
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .6rem;
|
||||
}
|
||||
|
||||
.info-list li {
|
||||
background: rgba(255, 255, 255, .08);
|
||||
padding: .6rem 1rem;
|
||||
border-radius: 12px;
|
||||
font-weight: 600;
|
||||
font-size: .9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.info-footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.mini-badge {
|
||||
border: 1px solid var(--dance-yellow);
|
||||
color: var(--dance-yellow-light);
|
||||
padding: .25rem .8rem;
|
||||
border-radius: 999px;
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.event-banner {
|
||||
padding: 1.75rem 1.25rem;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.event-banner h2 {
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.form-panel,
|
||||
.info-card {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="crystal-dance-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">SECHSKIES DANCE ARCHIVE & 30TH FAN PROJECT</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="portal-nav" aria-label="瘞湔?瑕酋?典誨?典?閬? data-portal-nav></nav>
|
||||
|
||||
<canvas id="particles"></canvas>
|
||||
|
||||
<main class="content-container crystal-dance-main">
|
||||
|
||||
<section class="crystal-dance-hero">
|
||||
<span class="category-tag">瘞湔?瑕酋?典誨?具???隡?</span>
|
||||
<p class="hero-desc">瘞湔?梯?蝷暹瘞湔?瑕酋?典誨?其葉??頩??港???敺?20TH
|
||||
?啁撠?銝脩??航???擃??嗅?潘??渡?蝬??蕃頝喟????銵?嚗蒂????2027/04/15 30TH ???????/p>
|
||||
|
||||
<nav class="quick-nav" aria-label="?撠汗">
|
||||
<a href="#about" class="btn btn-outline-dance btn-sm">02 ?梯?蝷曆?蝝?/a>
|
||||
<a href="#throwback-20th" class="btn btn-outline-dance btn-sm">03 20TH 敶梁??“</a>
|
||||
<a href="#song-archive" class="btn btn-outline-dance btn-sm">04 蝬??</a>
|
||||
<a href="#project-30th" class="btn btn-outline-dance btn-sm">05 30TH ?隡?</a>
|
||||
<a href="#form-30th" class="btn btn-outline-dance btn-sm">06 ???銵典</a>
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<!-- 02 ?梯?蝷曆?蝝?-->
|
||||
<section id="about" class="section-alt">
|
||||
<div class="section-kicker">02 繚 ?梯?蝷曆?蝝?/div>
|
||||
<h2 class="section-title">瘞湔?梯?蝷曆??臭??祉冗??/h2>
|
||||
<p class="section-lead">瘞湔?梯?蝷曆??舐蝡?蝡?蝷曉?嚗?偌?嗥摮拇撱???銝????蕃頝喋??渲?敶梁?蝝??憿?航? SECHSKIES
|
||||
????毀蝧??曇?蝝???賣?鋡急?脤??ㄐ嚗甇瑕??啁撠??亙??渡??辣蝥?/p>
|
||||
<div class="keyword-row d-flex flex-wrap gap-2">
|
||||
<span class="keyword-chip">?? 蝬?</span>
|
||||
<span class="keyword-chip">? ???</span>
|
||||
<span class="keyword-chip">? 蝧餉歲蝝??/span>
|
||||
<span class="keyword-chip">?? 銝脩??航?</span>
|
||||
<span class="keyword-chip">?? ?啁撠?</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 03 20TH 敶梁??“ -->
|
||||
<section id="throwback-20th">
|
||||
<div class="section-kicker">03 繚 20TH 敶梁??“</div>
|
||||
<h2 class="section-title">20TH 敶梁??“</h2>
|
||||
<p class="section-lead">2017 撟湛??啁撠?隞交偌?嗥摮拙??20 ?典僑?箏?璈?蝐齒鈭??豢??脖葡????氬??芣銝甈∟歲?暑??????乓?敺?甇貉???賊?瞈葬?典?銝?臬蔣?ㄐ??擃??嗚?/p>
|
||||
<p class="section-lead">瘞湔?梯?蝷曉??辣蝥遢閮嚗? 20TH ?銵銵??渡??隞亥◤?活??????銋 2027/04/15 ??30TH ?隡????啁?????/p>
|
||||
|
||||
<div class="row g-4 mt-1">
|
||||
<div class="col-12 col-sm-6">
|
||||
<div class="video-card">
|
||||
<span class="video-tag">20TH ??敶梁?</span>
|
||||
<div class="ratio ratio-16x9">
|
||||
<iframe src="https://www.youtube.com/embed/ARi0cfpv6mE" title="20TH ??敶梁?"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<div class="video-card">
|
||||
<span class="video-tag">20TH 甇??敶梁?</span>
|
||||
<div class="ratio ratio-16x9">
|
||||
<iframe src="https://www.youtube.com/embed/fkJmOMPirBc" title="20TH 甇??敶梁?"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 04 蝬?? -->
|
||||
<section id="song-archive" class="section-alt">
|
||||
<div class="section-kicker">04 繚 蝬??</div>
|
||||
<h2 class="section-title">蝬??</h2>
|
||||
<p class="section-lead">隞乩??撟暸??冽??渲?蝧餉歲銝剜?撣詨?曄??嚗???30TH 蝺渡??葡??楊?????柴?/p>
|
||||
|
||||
<div class="row g-4 mt-1">
|
||||
<div class="col-12 col-sm-6 col-lg-3">
|
||||
<div class="song-card">
|
||||
<span class="song-meta">??啗情</span>
|
||||
<h4>Couple</h4>
|
||||
<p>頛翰???望??嚗??貊??犖鈭?韏唬?嚗虜鋡怠?脫風撟渡????嗆捏?毽?芸蔣?ㄐ??/p>
|
||||
<span class="song-meta">?拙???</span>
|
||||
<p>??憟質???敶Z???銴?嚗??拙??嗡???????脩??/p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-lg-3">
|
||||
<div class="song-card">
|
||||
<span class="song-meta">??啗情</span>
|
||||
<h4>Com' Back</h4>
|
||||
<p>?飛?隞?”?脖?銝嚗?憟?敹怒??撘瘀?敺捆?葆??湔除瘞?/p>
|
||||
<span class="song-meta">?拙???</span>
|
||||
<p>?舀????折?嚗停蝞蝚砌?甈∪????渡?撠?銋敹恍?銝?/p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-lg-3">
|
||||
<div class="song-card">
|
||||
<span class="song-meta">??啗情</span>
|
||||
<h4>Road Fighter</h4>
|
||||
<p>??撟漲憭扼?憟?敹恬??舫???暺???嚗??唳除?W?頞喋?/p>
|
||||
<span class="song-meta">?拙???</span>
|
||||
<p>?拙?撌脫??箇?????蝺渲絲靘??擛交?嚗??拙??曉銝脩???頠詻?/p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-lg-3">
|
||||
<div class="song-card">
|
||||
<span class="song-meta">??啗情</span>
|
||||
<h4>Pom Saeng Pom Sa</h4>
|
||||
<p>??敺??朣?敶g??舫?甇甇瑕僑蝧餉歲銝剛◤??憭活????銝??/p>
|
||||
<span class="song-meta">?拙???</span>
|
||||
<p>颲刻?摨阡?嚗?其葡???銝剜挾敺捆???勗?湔除瘞?/p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 05 30TH ?隡? -->
|
||||
<section id="project-30th">
|
||||
<div class="section-kicker">05 繚 30TH ?隡?</div>
|
||||
<h2 class="section-title">30TH ???</h2>
|
||||
<p class="section-lead">2027/04/15 ??SECHSKIES ?粹? 30 ?典僑?摮偌?嗥?冗????30TH
|
||||
???唳??頩??游摰對????喃?韏瑕????啁撠?嚗?蝬??蕃頝喟毀蝧蔣?頛臬蟡???嚗??啁??銵?敺遢銵典??蝝舐???/p>
|
||||
<p class="section-lead">雿??閬???撠勗??歲???芾???敺偌?嗥摮拍?????莎?????雿???祇?嚗?臭誑?券ㄐ??雿????孵???/p>
|
||||
<div class="countdown-strip" id="countdown">?? 頝 30TH 繚 2027/04/15 ?閮?銝?..</div>
|
||||
</section>
|
||||
|
||||
<!-- 06 30TH ???銵典 -->
|
||||
<section id="form-30th" class="section-alt">
|
||||
<div class="section-kicker">06 繚 30TH ???銵典</div>
|
||||
|
||||
<div class="event-banner mb-4">
|
||||
<span class="event-badge">?? SECHSKIES 30TH 繚 2027.04.15</span>
|
||||
<h2>30TH ???銵典</h2>
|
||||
<p>?遢銵典?舀偌?嗥?冗??2027/04/15 30TH ?????游??芋蝯??其??渡????蝺渡?甇??舀?摰寡??喟?銝?蟡???/p>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-sm-7">
|
||||
<div class="form-panel">
|
||||
<h3 class="panel-title">?? ???鞈?</h3>
|
||||
<form action="#">
|
||||
<div class="row g-3">
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="nickname" class="form-label">?梁迂</label>
|
||||
<input type="text" class="form-control" id="nickname" name="nickname"
|
||||
placeholder="靘??梯?撠?" required>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email"
|
||||
placeholder="dance@example.com" required>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="dance_years" class="form-label">蝺渲?蝬?撟湔</label>
|
||||
<input type="number" class="form-control" id="dance_years" name="dance_years"
|
||||
min="0" max="30" placeholder="0">
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="available_date" class="form-label">?臬????/label>
|
||||
<input type="date" class="form-control" id="available_date" name="available_date">
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label class="form-label d-block">?臬????20TH</label>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<input type="radio" class="btn-check" name="attended_20th"
|
||||
id="attended_20th_yes" value="attended" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="attended_20th_yes">????20TH</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="attended_20th"
|
||||
id="attended_20th_video" value="watched_video" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="attended_20th_video">?? 20TH
|
||||
敶梁?</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="attended_20th"
|
||||
id="attended_20th_first" value="first_time" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="attended_20th_first">蝚砌?甈∠??/label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label class="form-label d-block">?喳??? 30TH ?批捆嚗銴嚗?/label>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_cover" value="cover" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_cover">蝧餉歲</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_medley" value="medley" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_medley">銝脩??航?</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_blessing" value="blessing" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_blessing">蟡?敶梁?</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_graphic" value="graphic" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_graphic">???</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_editing" value="editing" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_editing">敶梁??芾摩</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" name="participate_content"
|
||||
id="content_archive" value="archive" autocomplete="off">
|
||||
<label class="btn btn-outline-dance" for="content_archive">鞈??渡?</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="song" class="form-label">?喟毀????/label>
|
||||
<select class="form-select" id="song" name="song">
|
||||
<option value="" selected>隢????/option>
|
||||
<option value="couple">Couple</option>
|
||||
<option value="comeback">Com' Back</option>
|
||||
<option value="road_fighter">Road Fighter</option>
|
||||
<option value="pom_saeng_pom_sa">Pom Saeng Pom Sa</option>
|
||||
<option value="other">?嗡?</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label for="reference_file" class="form-label">銝?蔣????</label>
|
||||
<input class="form-control" type="file" id="reference_file" name="reference_file"
|
||||
accept="image/*,video/*">
|
||||
<div class="form-text">蝧餉歲敶梁????啁???芾摩蝝??</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label for="message_30th" class="form-label">?喳? 30TH 隤芰?閰?/label>
|
||||
<textarea class="form-control" id="message_30th" name="message_30th" rows="4"
|
||||
placeholder="?喳?瘞湔?梯?蝷曇牧?店?鞎Y??閬隤啜????蝳色?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid d-sm-flex gap-3 mt-4">
|
||||
<button type="reset"
|
||||
class="btn btn-reset-dance flex-fill order-2 order-sm-1">?憛怠神</button>
|
||||
<button type="submit"
|
||||
class="btn btn-dance flex-fill order-1 order-sm-2">??銵典 ??</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-5">
|
||||
<div class="info-card">
|
||||
<span class="info-tag">憛怠神?</span>
|
||||
<h3>???蝣箄?銝銝?/h3>
|
||||
<ul class="info-list">
|
||||
<li>?? 瑼??澆?嚗蔣?????嚗遣霅啣瑼?100MB 隞亙</li>
|
||||
<li>?? ?遢鞈???瘞湔?梯?蝷曉?冽??30TH ?隡?雿輻</li>
|
||||
<li>?? ?敺蝣箏???嚗?敺??西??砍?蝺渡???鋆賣???/li>
|
||||
</ul>
|
||||
<div class="info-footer">
|
||||
<span class="mini-badge">瘞湔?瑕酋?典誨??/span>
|
||||
<span class="mini-badge">30TH ?隡?</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>SECHSKIES Fanpage © 2026 - 暺瘞??瘞賊?憌?</p>
|
||||
<a href="https://jekkinoopy.github.io/Portfolio/" class="studio-link" target="_blank" rel="noopener noreferrer">
|
||||
Design by <span class="mark_b">Jekkinoopy Studio</span>
|
||||
</a>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../assets/js/particles.js"></script>
|
||||
<script src="../assets/js/portal-nav.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var target = new Date('2027-04-15T00:00:00+08:00');
|
||||
var now = new Date();
|
||||
var diffDays = Math.ceil((target - now) / (1000 * 60 * 60 * 24));
|
||||
var el = document.getElementById('countdown');
|
||||
if (el) {
|
||||
el.textContent = diffDays > 0
|
||||
? '?? 頝 30TH 繚 2027/04/15 ?? ' + diffDays + ' 憭?
|
||||
: '?? 30TH 繚 2027/04/15 撌脩??唬?嚗?韏瑕???嚗?;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,170 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$config = require __DIR__ . '/../admin/config.php';
|
||||
|
||||
function return_to_dance_form(string $result): never
|
||||
{
|
||||
header('Location: crystal-dance-survey.html?form=' . rawurlencode($result) . '#form-30th', true, 303);
|
||||
exit;
|
||||
}
|
||||
|
||||
function post_value(string $key, int $maxLength): string
|
||||
{
|
||||
$value = trim((string) ($_POST[$key] ?? ''));
|
||||
return mb_substr($value, 0, $maxLength, 'UTF-8');
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
header('Allow: POST');
|
||||
exit('Method Not Allowed');
|
||||
}
|
||||
|
||||
$maxUploadBytes = (int) $config['dance_max_upload_bytes'];
|
||||
$contentLength = (int) ($_SERVER['CONTENT_LENGTH'] ?? 0);
|
||||
if ($contentLength > $maxUploadBytes + 1024 * 1024) {
|
||||
return_to_dance_form('file_too_large');
|
||||
}
|
||||
|
||||
// 隱藏欄位有內容時視為機器送件;不透露攔截規則。
|
||||
if (trim((string) ($_POST['website'] ?? '')) !== '') {
|
||||
return_to_dance_form('success');
|
||||
}
|
||||
|
||||
$nickname = post_value('nickname', 80);
|
||||
$email = mb_strtolower(post_value('email', 190), 'UTF-8');
|
||||
$danceYearsRaw = trim((string) ($_POST['dance_years'] ?? ''));
|
||||
$availableDate = trim((string) ($_POST['available_date'] ?? ''));
|
||||
$attended20th = trim((string) ($_POST['attended_20th'] ?? ''));
|
||||
$song = trim((string) ($_POST['song'] ?? ''));
|
||||
$message30th = post_value('message_30th', 5000);
|
||||
|
||||
$allowedAttendance = ['attended', 'watched_video', 'first_time'];
|
||||
$allowedContent = ['cover', 'medley', 'blessing', 'graphic', 'editing', 'archive'];
|
||||
$allowedSongs = ['', 'couple', 'comeback', 'road_fighter', 'pom_saeng_pom_sa', 'other'];
|
||||
|
||||
$selectedContent = $_POST['participate_content'] ?? [];
|
||||
if (!is_array($selectedContent)) {
|
||||
$selectedContent = [$selectedContent];
|
||||
}
|
||||
$selectedContent = array_values(array_unique(array_intersect(
|
||||
$allowedContent,
|
||||
array_map(static fn ($value): string => trim((string) $value), $selectedContent)
|
||||
)));
|
||||
|
||||
if ($nickname === '' || !filter_var($email, FILTER_VALIDATE_EMAIL) || !$selectedContent) {
|
||||
return_to_dance_form('invalid');
|
||||
}
|
||||
if ($attended20th !== '' && !in_array($attended20th, $allowedAttendance, true)) {
|
||||
return_to_dance_form('invalid');
|
||||
}
|
||||
if (!in_array($song, $allowedSongs, true)) {
|
||||
return_to_dance_form('invalid');
|
||||
}
|
||||
|
||||
$danceYears = null;
|
||||
if ($danceYearsRaw !== '') {
|
||||
$danceYearsFilter = filter_var($danceYearsRaw, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0, 'max_range' => 30]]);
|
||||
if ($danceYearsFilter === false) {
|
||||
return_to_dance_form('invalid');
|
||||
}
|
||||
$danceYears = (int) $danceYearsFilter;
|
||||
}
|
||||
|
||||
if ($availableDate !== '') {
|
||||
$date = DateTimeImmutable::createFromFormat('!Y-m-d', $availableDate);
|
||||
if (!$date || $date->format('Y-m-d') !== $availableDate) {
|
||||
return_to_dance_form('invalid');
|
||||
}
|
||||
}
|
||||
|
||||
$db = $config['db'];
|
||||
$dsn = "mysql:host={$db['host']};port={$db['port']};dbname={$db['name']};charset=utf8mb4";
|
||||
try {
|
||||
$pdo = new PDO($dsn, $db['user'], $db['pass'], [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
]);
|
||||
} catch (PDOException) {
|
||||
return_to_dance_form('unavailable');
|
||||
}
|
||||
|
||||
$submittedIp = mb_substr((string) ($_SERVER['REMOTE_ADDR'] ?? ''), 0, 45, 'UTF-8');
|
||||
if ($submittedIp !== '') {
|
||||
$rate = $pdo->prepare('SELECT COUNT(*) FROM dance_applications WHERE submitted_ip = ? AND created_at >= DATE_SUB(NOW(), INTERVAL 2 MINUTE)');
|
||||
$rate->execute([$submittedIp]);
|
||||
if ((int) $rate->fetchColumn() >= 3) {
|
||||
return_to_dance_form('too_many');
|
||||
}
|
||||
}
|
||||
|
||||
$storedFileName = null;
|
||||
$originalFileName = null;
|
||||
$mimeType = null;
|
||||
$fileSize = null;
|
||||
$file = $_FILES['reference_file'] ?? null;
|
||||
if (is_array($file) && (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
|
||||
if ((int) $file['error'] !== UPLOAD_ERR_OK || (int) $file['size'] > $maxUploadBytes) {
|
||||
return_to_dance_form('file_too_large');
|
||||
}
|
||||
|
||||
$allowedMimeTypes = [
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif',
|
||||
'image/webp' => 'webp',
|
||||
'video/mp4' => 'mp4',
|
||||
'video/webm' => 'webm',
|
||||
'video/quicktime' => 'mov',
|
||||
];
|
||||
$mimeType = (new finfo(FILEINFO_MIME_TYPE))->file((string) $file['tmp_name']) ?: '';
|
||||
if (!isset($allowedMimeTypes[$mimeType])) {
|
||||
return_to_dance_form('file_type');
|
||||
}
|
||||
|
||||
$uploadDir = (string) $config['dance_upload_dir'];
|
||||
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0750, true) && !is_dir($uploadDir)) {
|
||||
return_to_dance_form('unavailable');
|
||||
}
|
||||
$storedFileName = bin2hex(random_bytes(20)) . '.' . $allowedMimeTypes[$mimeType];
|
||||
if (!move_uploaded_file((string) $file['tmp_name'], $uploadDir . DIRECTORY_SEPARATOR . $storedFileName)) {
|
||||
return_to_dance_form('unavailable');
|
||||
}
|
||||
$originalFileName = mb_substr(basename((string) $file['name']), 0, 255, 'UTF-8');
|
||||
$fileSize = (int) $file['size'];
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare(
|
||||
'INSERT INTO dance_applications
|
||||
(nickname, email, dance_years, available_date, attended_20th, participate_content, song,
|
||||
reference_file_name, reference_original_name, reference_mime_type, reference_file_size,
|
||||
message_30th, submitted_ip, user_agent)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||||
);
|
||||
$stmt->execute([
|
||||
$nickname,
|
||||
$email,
|
||||
$danceYears,
|
||||
$availableDate !== '' ? $availableDate : null,
|
||||
$attended20th !== '' ? $attended20th : null,
|
||||
implode(',', $selectedContent),
|
||||
$song !== '' ? $song : null,
|
||||
$storedFileName,
|
||||
$originalFileName,
|
||||
$mimeType,
|
||||
$fileSize,
|
||||
$message30th !== '' ? $message30th : null,
|
||||
$submittedIp !== '' ? $submittedIp : null,
|
||||
mb_substr((string) ($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255, 'UTF-8'),
|
||||
]);
|
||||
} catch (PDOException) {
|
||||
if ($storedFileName !== null) {
|
||||
@unlink((string) $config['dance_upload_dir'] . DIRECTORY_SEPARATOR . $storedFileName);
|
||||
}
|
||||
return_to_dance_form('unavailable');
|
||||
}
|
||||
|
||||
return_to_dance_form('success');
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store');
|
||||
|
||||
$config = require __DIR__ . '/../admin/config.php';
|
||||
$db = $config['db'];
|
||||
$dsn = "mysql:host={$db['host']};port={$db['port']};dbname={$db['name']};charset=utf8mb4";
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $db['user'], $db['pass'], [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
]);
|
||||
$rows = $pdo->query(
|
||||
"SELECT id, title, tags, practice_focus, video_url, difficulty, progress_status,
|
||||
note_text, is_featured, sort_order, status
|
||||
FROM dance_practice_items
|
||||
WHERE status IN ('published', 'coming_soon')
|
||||
ORDER BY sort_order, id"
|
||||
)->fetchAll();
|
||||
} catch (PDOException) {
|
||||
http_response_code(503);
|
||||
echo json_encode(['ok' => false, 'items' => []], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$difficultyLabels = ['easy' => '入門', 'medium' => '中等', 'hard' => '挑戰'];
|
||||
$progressLabels = ['not_started' => '未開始', 'practicing' => '練習中', 'review' => '待複習', 'completed' => '已完成'];
|
||||
|
||||
$items = array_map(static function (array $row) use ($difficultyLabels, $progressLabels): array {
|
||||
$videoUrl = trim((string) ($row['video_url'] ?? ''));
|
||||
if ($videoUrl !== '' && (!filter_var($videoUrl, FILTER_VALIDATE_URL) || !preg_match('/^https?:\/\//i', $videoUrl))) {
|
||||
$videoUrl = '';
|
||||
}
|
||||
return [
|
||||
'id' => (int) $row['id'],
|
||||
'title' => (string) $row['title'],
|
||||
'tags' => array_values(array_filter(array_map('trim', explode(',', (string) ($row['tags'] ?? ''))))),
|
||||
'practiceFocus' => (string) $row['practice_focus'],
|
||||
'videoUrl' => $videoUrl,
|
||||
'difficulty' => $difficultyLabels[$row['difficulty']] ?? (string) $row['difficulty'],
|
||||
'progress' => $progressLabels[$row['progress_status']] ?? (string) $row['progress_status'],
|
||||
'note' => (string) ($row['note_text'] ?? ''),
|
||||
'featured' => (bool) $row['is_featured'],
|
||||
'comingSoon' => $row['status'] === 'coming_soon',
|
||||
];
|
||||
}, $rows);
|
||||
|
||||
echo json_encode(['ok' => true, 'items' => $items], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
Reference in New Issue
Block a user