Files
ewoooc/templates/components/_loading.html
OoO f7726bea3f
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
fix: 收斂登入與載入元件新版視覺
2026-05-17 21:22:03 +08:00

349 lines
9.2 KiB
HTML
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{#
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>