349 lines
9.2 KiB
HTML
Executable File
349 lines
9.2 KiB
HTML
Executable File
{#
|
||
WOOO 品牌載入動畫組件
|
||
|
||
使用方式:
|
||
1. 在頁面中 include 此組件:
|
||
{% include 'components/_loading.html' %}
|
||
|
||
2. 在 JavaScript 中控制顯示/隱藏:
|
||
showLoading('正在載入數據...') // 顯示
|
||
hideLoading() // 隱藏
|
||
|
||
3. 也可直接操作 DOM:
|
||
document.getElementById('loadingOverlay').style.display = 'flex'; // 顯示
|
||
document.getElementById('loadingOverlay').style.display = 'none'; // 隱藏
|
||
#}
|
||
|
||
<!-- WOOO Loading Overlay -->
|
||
<div id="loadingOverlay" class="wooo-loading-overlay">
|
||
<div class="loading-logo-container">
|
||
<!-- 脈衝光暈 -->
|
||
<div class="logo-pulse"></div>
|
||
<!-- 外層旋轉光環 -->
|
||
<div class="logo-ring"></div>
|
||
<!-- 內層反向旋轉光環 -->
|
||
<div class="logo-ring-inner"></div>
|
||
<!-- 環繞粒子 -->
|
||
<div class="orbit-particles">
|
||
<div class="orbit-particle"></div>
|
||
<div class="orbit-particle"></div>
|
||
<div class="orbit-particle"></div>
|
||
<div class="orbit-particle"></div>
|
||
</div>
|
||
<!-- 閃爍星星 -->
|
||
<div class="sparkles">
|
||
<div class="sparkle"></div>
|
||
<div class="sparkle"></div>
|
||
<div class="sparkle"></div>
|
||
<div class="sparkle"></div>
|
||
<div class="sparkle"></div>
|
||
<div class="sparkle"></div>
|
||
</div>
|
||
<!-- LOGO -->
|
||
<div class="loading-logo">WOOO</div>
|
||
</div>
|
||
<div class="loading-text" id="loadingText">
|
||
<i class="fas fa-spinner fa-spin me-2"></i>正在載入數據...
|
||
</div>
|
||
<div class="loading-progress">
|
||
<div class="loading-progress-bar"></div>
|
||
</div>
|
||
<div class="loading-hint" id="loadingHint">
|
||
大量資料可能需要較長時間,請稍候
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
/* ============================================
|
||
WOOO 品牌載入動畫樣式
|
||
============================================ */
|
||
|
||
.wooo-loading-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(240, 235, 225, 0.94);
|
||
background-image: radial-gradient(circle, rgba(42, 37, 32, 0.14) 1px, transparent 1.5px);
|
||
background-size: 18px 18px;
|
||
z-index: 9999;
|
||
display: none;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 20px;
|
||
backdrop-filter: blur(6px);
|
||
}
|
||
|
||
/* LOGO 動畫容器 */
|
||
.wooo-loading-overlay .loading-logo-container {
|
||
position: relative;
|
||
width: 144px;
|
||
height: 144px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.wooo-loading-overlay .loading-logo {
|
||
z-index: 3;
|
||
animation: wooo-cloud-float 3s ease-in-out infinite;
|
||
color: var(--momo-ink);
|
||
font-size: 2.35rem;
|
||
font-weight: 800;
|
||
font-family: var(--momo-font-display, "Noto Sans TC", "Inter", system-ui, sans-serif);
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
/* 雲端飄動動畫 */
|
||
@keyframes wooo-cloud-float {
|
||
0%, 100% {
|
||
transform: translateY(0) translateX(0) scale(1);
|
||
}
|
||
25% {
|
||
transform: translateY(-15px) translateX(5px) scale(1.02);
|
||
}
|
||
50% {
|
||
transform: translateY(-8px) translateX(-3px) scale(1);
|
||
}
|
||
75% {
|
||
transform: translateY(-20px) translateX(3px) scale(1.01);
|
||
}
|
||
}
|
||
|
||
/* 外層旋轉光環 */
|
||
.wooo-loading-overlay .logo-ring {
|
||
position: absolute;
|
||
width: 138px;
|
||
height: 138px;
|
||
border: 2px solid transparent;
|
||
border-top-color: var(--momo-page-accent, var(--momo-warm-caramel));
|
||
border-right-color: var(--momo-ink);
|
||
border-radius: 50%;
|
||
animation: wooo-ring-spin 2s linear infinite;
|
||
}
|
||
|
||
/* 內層反向旋轉光環 */
|
||
.wooo-loading-overlay .logo-ring-inner {
|
||
position: absolute;
|
||
width: 110px;
|
||
height: 110px;
|
||
border: 1px solid transparent;
|
||
border-bottom-color: var(--momo-warm-honey);
|
||
border-left-color: var(--momo-success);
|
||
border-radius: 50%;
|
||
animation: wooo-ring-spin-reverse 1.5s linear infinite;
|
||
}
|
||
|
||
/* 脈衝光暈 */
|
||
.wooo-loading-overlay .logo-pulse {
|
||
position: absolute;
|
||
width: 92px;
|
||
height: 92px;
|
||
border: 1px solid var(--momo-page-accent-line, rgba(201, 100, 66, 0.32));
|
||
background: var(--momo-page-accent-soft, rgba(201, 100, 66, 0.12));
|
||
border-radius: 50%;
|
||
animation: wooo-pulse-expand 2s ease-out infinite;
|
||
}
|
||
|
||
@keyframes wooo-ring-spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
@keyframes wooo-ring-spin-reverse {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(-360deg); }
|
||
}
|
||
|
||
@keyframes wooo-pulse-expand {
|
||
0% {
|
||
transform: scale(0.8);
|
||
opacity: 1;
|
||
}
|
||
100% {
|
||
transform: scale(1.8);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
/* 環繞粒子 */
|
||
.wooo-loading-overlay .orbit-particles {
|
||
position: absolute;
|
||
width: 144px;
|
||
height: 144px;
|
||
animation: wooo-orbit-rotate 4s linear infinite;
|
||
}
|
||
|
||
.wooo-loading-overlay .orbit-particle {
|
||
position: absolute;
|
||
width: 7px;
|
||
height: 7px;
|
||
background: var(--momo-page-accent, var(--momo-warm-caramel));
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.wooo-loading-overlay .orbit-particle:nth-child(1) {
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.wooo-loading-overlay .orbit-particle:nth-child(2) {
|
||
top: 50%;
|
||
right: 0;
|
||
transform: translateY(-50%);
|
||
}
|
||
|
||
.wooo-loading-overlay .orbit-particle:nth-child(3) {
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.wooo-loading-overlay .orbit-particle:nth-child(4) {
|
||
top: 50%;
|
||
left: 0;
|
||
transform: translateY(-50%);
|
||
}
|
||
|
||
@keyframes wooo-orbit-rotate {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* 閃爍星星 */
|
||
.wooo-loading-overlay .sparkles {
|
||
position: absolute;
|
||
width: 166px;
|
||
height: 166px;
|
||
}
|
||
|
||
.wooo-loading-overlay .sparkle {
|
||
position: absolute;
|
||
width: 4px;
|
||
height: 4px;
|
||
background: var(--momo-warm-honey);
|
||
border-radius: 50%;
|
||
animation: wooo-sparkle-twinkle 1.5s ease-in-out infinite;
|
||
}
|
||
|
||
.wooo-loading-overlay .sparkle:nth-child(1) { top: 10%; left: 20%; animation-delay: 0s; }
|
||
.wooo-loading-overlay .sparkle:nth-child(2) { top: 5%; right: 25%; animation-delay: 0.3s; }
|
||
.wooo-loading-overlay .sparkle:nth-child(3) { bottom: 15%; right: 15%; animation-delay: 0.6s; }
|
||
.wooo-loading-overlay .sparkle:nth-child(4) { bottom: 10%; left: 25%; animation-delay: 0.9s; }
|
||
.wooo-loading-overlay .sparkle:nth-child(5) { top: 30%; left: 5%; animation-delay: 1.2s; }
|
||
.wooo-loading-overlay .sparkle:nth-child(6) { top: 25%; right: 5%; animation-delay: 0.4s; }
|
||
|
||
@keyframes wooo-sparkle-twinkle {
|
||
0%, 100% {
|
||
transform: scale(0);
|
||
opacity: 0;
|
||
}
|
||
50% {
|
||
transform: scale(1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
/* 載入文字 */
|
||
.wooo-loading-overlay .loading-text {
|
||
color: var(--momo-text-primary);
|
||
font-family: var(--momo-font-display, "Noto Sans TC", "Inter", system-ui, sans-serif);
|
||
font-size: 1rem;
|
||
font-weight: 780;
|
||
text-align: center;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.wooo-loading-overlay .loading-hint {
|
||
font-size: 0.85rem;
|
||
color: var(--momo-text-secondary);
|
||
text-align: center;
|
||
max-width: 300px;
|
||
}
|
||
|
||
/* 進度條 */
|
||
.wooo-loading-overlay .loading-progress {
|
||
width: 200px;
|
||
height: 4px;
|
||
background: var(--momo-border-light);
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.wooo-loading-overlay .loading-progress-bar {
|
||
height: 100%;
|
||
background: var(--momo-page-accent, var(--momo-warm-caramel));
|
||
animation: wooo-progress-flow 1.5s linear infinite;
|
||
width: 100%;
|
||
}
|
||
|
||
@keyframes wooo-progress-flow {
|
||
0% { transform: translateX(-100%); }
|
||
100% { transform: translateX(100%); }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.wooo-loading-overlay .loading-logo,
|
||
.wooo-loading-overlay .logo-ring,
|
||
.wooo-loading-overlay .logo-ring-inner,
|
||
.wooo-loading-overlay .logo-pulse,
|
||
.wooo-loading-overlay .orbit-particles,
|
||
.wooo-loading-overlay .sparkle,
|
||
.wooo-loading-overlay .loading-progress-bar {
|
||
animation-duration: 0.01ms;
|
||
animation-iteration-count: 1;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
/**
|
||
* WOOO 載入動畫控制函數
|
||
*/
|
||
|
||
// 顯示載入動畫
|
||
function showLoading(text, hint) {
|
||
const overlay = document.getElementById('loadingOverlay');
|
||
const loadingText = document.getElementById('loadingText');
|
||
const loadingHint = document.getElementById('loadingHint');
|
||
|
||
if (text && loadingText) {
|
||
loadingText.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>' + text;
|
||
}
|
||
if (hint && loadingHint) {
|
||
loadingHint.textContent = hint;
|
||
}
|
||
|
||
if (overlay) {
|
||
overlay.style.display = 'flex';
|
||
}
|
||
}
|
||
|
||
// 隱藏載入動畫
|
||
function hideLoading() {
|
||
const overlay = document.getElementById('loadingOverlay');
|
||
if (overlay) {
|
||
overlay.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 更新載入文字
|
||
function updateLoadingText(text) {
|
||
const loadingText = document.getElementById('loadingText');
|
||
if (loadingText && text) {
|
||
loadingText.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>' + text;
|
||
}
|
||
}
|
||
|
||
// 更新載入提示
|
||
function updateLoadingHint(hint) {
|
||
const loadingHint = document.getElementById('loadingHint');
|
||
if (loadingHint && hint) {
|
||
loadingHint.textContent = hint;
|
||
}
|
||
}
|
||
</script>
|