Files
xianyan/design-preview/editor-bottom-toolbar-arc.html
Developer b5157c19f4 feat: 新增壁纸图库组件和编辑器功能优化
- 新增壁纸图库相关组件(WallpaperGalleryView/WallpaperSearchBar等)
- 优化编辑器主题服务和系统UI管理
- 新增虚线边框和拖拽描边风格支持
- 完善今日诗词服务和阅读报告功能
- 修复多个UI问题和空指针异常
- 更新依赖库版本和SVG资源
- 优化交互动画和状态管理
- 补充文档和API测试脚本
2026-05-05 05:03:33 +08:00

838 lines
24 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>编辑器底部工具栏 — 方案B 弧形分页滑动 (Liquid Glass)</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=SF+Pro+Display:wght@300;400;500;600;700&display=swap');
:root {
--accent: #40C4FF;
--accent-deep: #0091EA;
--accent-glow: rgba(64, 196, 255, 0.25);
--glass-bg: rgba(255, 255, 255, 0.06);
--glass-border: rgba(255, 255, 255, 0.12);
--glass-highlight: rgba(255, 255, 255, 0.18);
--text-primary: rgba(255, 255, 255, 0.9);
--text-secondary: rgba(255, 255, 255, 0.5);
--text-tertiary: rgba(255, 255, 255, 0.3);
--safe-bottom: 34px;
}
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body {
font-family: -apple-system, 'SF Pro Display', 'Helvetica Neue', sans-serif;
background: #000;
color: var(--text-primary);
overflow: hidden;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.phone-frame {
width: 393px;
height: 852px;
background: linear-gradient(160deg, #0a0a1a 0%, #0d1b2a 40%, #1b2838 100%);
border-radius: 44px;
overflow: hidden;
position: relative;
box-shadow: 0 0 0 3px #333, 0 0 0 6px #1a1a1a, 0 30px 80px rgba(0,0,0,0.6);
}
.editor-canvas {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.editor-canvas-text {
color: rgba(255,255,255,0.08);
font-size: 52px;
font-weight: 700;
letter-spacing: -1px;
}
/* ─── 方案标签 ─── */
.scheme-tabs {
position: absolute;
top: 60px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 6px;
z-index: 100;
}
.scheme-tab {
padding: 5px 14px;
border-radius: 18px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
border: 0.5px solid rgba(255,255,255,0.1);
background: rgba(28, 28, 30, 0.6);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
color: var(--text-secondary);
}
.scheme-tab.active {
background: var(--accent);
color: #fff;
border-color: var(--accent);
box-shadow: 0 2px 12px var(--accent-glow);
}
/* ─── 底部工具栏 ─── */
.bottom-toolbar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 50;
}
/* ─── Liquid Glass 底栏 ─── */
.glass-bar {
position: relative;
margin: 12px 12px 0;
border-radius: 28px;
overflow: visible;
}
.glass-bar-bg {
position: absolute;
inset: 0;
border-radius: 28px;
background: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(40px) saturate(180%);
-webkit-backdrop-filter: blur(40px) saturate(180%);
border: 0.5px solid rgba(255, 255, 255, 0.12);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.08),
inset 0 -1px 0 rgba(0,0,0,0.1),
0 8px 32px rgba(0,0,0,0.3);
}
/* ─── 弧形凸起区域 ─── */
.arc-bump {
position: absolute;
top: -22px;
left: 50%;
transform: translateX(-50%);
width: 72px;
height: 44px;
z-index: 10;
}
.arc-bump-bg {
width: 100%;
height: 100%;
border-radius: 50% 50% 0 0 / 100% 100% 0 0;
background: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(40px) saturate(180%);
-webkit-backdrop-filter: blur(40px) saturate(180%);
border: 0.5px solid rgba(255, 255, 255, 0.12);
border-bottom: none;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.1),
0 -4px 16px rgba(0,0,0,0.2);
}
.arc-toolbox-btn {
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%);
width: 48px;
height: 48px;
border-radius: 50%;
background: linear-gradient(135deg, var(--accent-deep), var(--accent));
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
cursor: pointer;
box-shadow:
0 4px 16px var(--accent-glow),
0 0 40px rgba(64, 196, 255, 0.1);
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
z-index: 20;
}
.arc-toolbox-btn:active {
transform: translateX(-50%) scale(0.88);
}
/* ─── 工具页面 ─── */
.tool-pages-container {
position: relative;
overflow: hidden;
height: 64px;
margin: 0 8px;
}
.tool-page {
position: absolute;
inset: 0;
display: flex;
justify-content: space-around;
align-items: center;
padding: 0 4px;
transition: transform 0.45s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.35s ease;
}
.tool-page.left {
transform: translateX(-100%);
opacity: 0;
}
.tool-page.center {
transform: translateX(0);
opacity: 1;
}
.tool-page.right {
transform: translateX(100%);
opacity: 0;
}
/* ─── 工具按钮 ─── */
.tool-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
padding: 6px 4px;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.32, 0.72, 0, 1);
position: relative;
min-width: 48px;
}
.tool-btn:active {
transform: scale(0.85);
}
.tool-btn .emoji {
font-size: 22px;
line-height: 1;
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
filter: drop-shadow(0 1px 3px rgba(0,0,0,0.4));
}
.tool-btn:active .emoji {
transform: scale(1.3) translateY(-2px);
}
.tool-btn .label {
font-size: 9px;
font-weight: 500;
color: var(--text-secondary);
letter-spacing: 0.2px;
}
.tool-btn.active .label {
color: var(--accent);
font-weight: 600;
}
/* ─── Liquid Glass 指示器 ─── */
.glass-indicator {
position: absolute;
height: 44px;
border-radius: 22px;
background: rgba(255, 255, 255, 0.1);
border: 0.5px solid rgba(255, 255, 255, 0.15);
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.12),
0 2px 8px rgba(0,0,0,0.2);
transition: all 0.4s cubic-bezier(0.32, 0.72, 0, 1);
z-index: 5;
pointer-events: none;
}
/* ─── 分页指示器 ─── */
.page-dots {
display: flex;
justify-content: center;
gap: 6px;
padding: 6px 0 2px;
}
.page-dot {
width: 6px;
height: 6px;
border-radius: 3px;
background: var(--text-tertiary);
transition: all 0.35s cubic-bezier(0.32, 0.72, 0, 1);
cursor: pointer;
}
.page-dot.active {
width: 20px;
background: var(--accent);
box-shadow: 0 0 8px var(--accent-glow);
}
/* ─── xycard 状态行 ─── */
.status-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 20px 3px;
min-height: 22px;
}
.status-left {
display: flex;
align-items: center;
gap: 4px;
font-size: 10px;
color: var(--text-tertiary);
}
.status-center {
display: flex;
align-items: center;
gap: 5px;
font-size: 10px;
}
.status-center .version-tag {
font-weight: 600;
letter-spacing: 0.6px;
color: var(--text-secondary);
}
.status-center .debug-btn {
font-size: 12px;
cursor: pointer;
opacity: 0.4;
transition: opacity 0.2s;
}
.status-center .debug-btn:hover { opacity: 0.8; }
.status-right {
display: flex;
align-items: center;
gap: 4px;
}
.panel-toggle {
width: 26px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
font-size: 11px;
cursor: pointer;
transition: all 0.2s;
color: var(--text-tertiary);
}
.panel-toggle.active {
background: rgba(64, 196, 255, 0.1);
color: var(--accent);
border: 0.5px solid rgba(64, 196, 255, 0.15);
}
/* ─── Home Indicator ─── */
.home-indicator {
width: 134px;
height: 5px;
margin: 3px auto 6px;
border-radius: 3px;
background: rgba(255, 255, 255, 0.12);
}
/* ─── 弧形形变动画 ─── */
.tool-btn.deforming .emoji {
animation: arcDeform 0.45s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes arcDeform {
0% { transform: translateY(0) scaleY(1); }
30% { transform: translateY(-8px) scaleY(1.15) scaleX(0.9); }
60% { transform: translateY(-12px) scaleY(1.2) scaleX(0.85); }
80% { transform: translateY(-6px) scaleY(1.1) scaleX(0.92); }
100% { transform: translateY(0) scaleY(1) scaleX(1); }
}
/* ─── 滑动形变效果 ─── */
.tool-btn.slide-deform .emoji {
animation: slideDeform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes slideDeform {
0% { transform: translateY(0) scale(1); }
20% { transform: translateY(4px) scale(0.92); }
50% { transform: translateY(-14px) scale(1.12) ; }
70% { transform: translateY(-8px) scale(1.05); }
100% { transform: translateY(0) scale(1); }
}
/* ─── 涟漪效果 ─── */
.ripple-effect {
position: absolute;
border-radius: 50%;
background: radial-gradient(circle, rgba(64, 196, 255, 0.3), transparent);
transform: scale(0);
animation: ripple 0.5s ease-out;
pointer-events: none;
}
@keyframes ripple {
to { transform: scale(2.5); opacity: 0; }
}
/* ─── 说明卡片 ─── */
.desc-card {
position: absolute;
top: 110px;
left: 16px;
right: 16px;
padding: 14px 16px;
background: rgba(28, 28, 30, 0.7);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 14px;
border: 0.5px solid rgba(255,255,255,0.08);
z-index: 100;
}
.desc-card h3 {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.desc-card p {
font-size: 11px;
color: var(--text-secondary);
line-height: 1.6;
}
.desc-card .features {
list-style: none;
margin-top: 8px;
}
.desc-card .features li {
font-size: 11px;
color: var(--text-secondary);
padding: 2px 0;
}
.desc-card .features li::before {
content: '✦ ';
color: var(--accent);
}
/* ─── 交互提示 ─── */
.hint {
position: absolute;
top: 90px;
left: 50%;
transform: translateX(-50%);
font-size: 11px;
color: var(--text-tertiary);
background: rgba(28, 28, 30, 0.6);
backdrop-filter: blur(16px);
padding: 5px 12px;
border-radius: 10px;
border: 0.5px solid rgba(255,255,255,0.06);
white-space: nowrap;
z-index: 100;
transition: opacity 0.5s;
}
</style>
</head>
<body>
<div class="phone-frame" id="phone">
<div class="editor-canvas">
<div class="editor-canvas-text">编辑区域</div>
</div>
<div class="scheme-tabs">
<div class="scheme-tab active" onclick="switchView('main')">主方案</div>
<div class="scheme-tab" onclick="switchView('compare')">对比旧版</div>
</div>
<div class="hint" id="hint">← 滑动切换分页 · 点击🧰打开工具箱 →</div>
<div class="desc-card" id="descCard">
<h3>方案B增强 — Liquid Glass 弧形分页</h3>
<p>使用 GlassBottomBar 风格,工具箱按钮在弧形凸起中央,滑动时按钮从弧形下方经过产生形变</p>
<ul class="features">
<li>GlassBottomBar 毛玻璃底栏 (与主页Tab一致)</li>
<li>弧形凸起区域 — 🧰工具箱居中悬浮</li>
<li>分页滑动 — 3页工具圆点指示器</li>
<li>弧形形变 — 按钮经过弧顶时弹性变形</li>
<li>xycard 1.0 状态行紧贴底栏下方</li>
<li>无多余空白,紧凑布局</li>
</ul>
</div>
<!-- 主方案 -->
<div class="bottom-toolbar" id="mainView">
<div class="glass-bar">
<div class="glass-bar-bg"></div>
<!-- 弧形凸起 + 工具箱按钮 -->
<div class="arc-bump">
<div class="arc-bump-bg"></div>
<div class="arc-toolbox-btn" onclick="tapToolbox()">🧰</div>
</div>
<!-- Glass Indicator -->
<div class="glass-indicator" id="indicator"></div>
<!-- 工具页面 -->
<div class="tool-pages-container" id="pagesContainer">
<!-- Page 1: 核心工具 -->
<div class="tool-page center" id="page0">
<div class="tool-btn active" onclick="tapTool(this, 0, 0)">
<span class="emoji">🖌️</span>
<span class="label">画笔</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 0, 1)">
<span class="emoji">📝</span>
<span class="label">文字</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 0, 2)">
<span class="emoji">✂️</span>
<span class="label">裁剪</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 0, 3)">
<span class="emoji">🎨</span>
<span class="label">色调</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 0, 4)">
<span class="emoji">🔍</span>
<span class="label">滤镜</span>
</div>
</div>
<!-- Page 2: 效果工具 -->
<div class="tool-page right" id="page1">
<div class="tool-btn" onclick="tapTool(this, 1, 0)">
<span class="emoji">🌫️</span>
<span class="label">模糊</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 1, 1)">
<span class="emoji">😀</span>
<span class="label">表情</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 1, 2)">
<span class="emoji">🎭</span>
<span class="label">贴纸</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 1, 3)">
<span class="emoji">🖼️</span>
<span class="label">壁纸</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 1, 4)">
<span class="emoji">🌈</span>
<span class="label">渐变</span>
</div>
</div>
<!-- Page 3: 高级工具 -->
<div class="tool-page right" id="page2">
<div class="tool-btn" onclick="tapTool(this, 2, 0)">
<span class="emoji">💧</span>
<span class="label">水印</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 2, 1)">
<span class="emoji"></span>
<span class="label">Shader</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 2, 2)">
<span class="emoji">📐</span>
<span class="label">画布</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 2, 3)">
<span class="emoji">🎯</span>
<span class="label">取色</span>
</div>
<div class="tool-btn" onclick="tapTool(this, 2, 4)">
<span class="emoji">🎨</span>
<span class="label">主题</span>
</div>
</div>
</div>
<!-- 分页指示器 -->
<div class="page-dots">
<div class="page-dot active" onclick="goPage(0)"></div>
<div class="page-dot" onclick="goPage(1)"></div>
<div class="page-dot" onclick="goPage(2)"></div>
</div>
</div>
<!-- xycard 状态行 -->
<div class="status-bar">
<div class="status-left">
<span>🖼️</span>
<span>PNG · 1080×1920</span>
</div>
<div class="status-center">
<span class="version-tag">xycard 1.0</span>
<span class="debug-btn" onclick="toggleDebug()"></span>
</div>
<div class="status-right">
<div class="panel-toggle active" onclick="togglePanel(this)">📍</div>
<div class="panel-toggle" onclick="togglePanel(this)"></div>
</div>
</div>
<div class="home-indicator"></div>
</div>
<!-- 对比旧版 -->
<div class="bottom-toolbar" id="compareView" style="display:none">
<div style="
margin: 0 8px;
padding: 6px 4px;
background: rgba(28,28,30,0.88);
backdrop-filter: blur(50px);
border-radius: 16px 16px 0 0;
border-top: 0.5px solid rgba(255,255,255,0.06);
">
<div style="display:flex; justify-content:space-around; align-items:flex-end; padding:0 4px;">
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">🖌️</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">画笔</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">📝</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">文字</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">✂️</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">裁剪</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">🎨</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">色调</div>
</div>
<div style="
width:52px; height:52px; border-radius:50%;
background:linear-gradient(135deg, #0091EA, #40C4FF);
display:flex; align-items:center; justify-content:center;
font-size:22px; margin-bottom:14px;
box-shadow: 0 4px 16px rgba(64,196,255,0.3);
">🧰</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">🔍</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">滤镜</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">🌫️</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">模糊</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">😀</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">表情</div>
</div>
<div style="text-align:center; padding:4px;">
<div style="font-size:20px;">🎭</div>
<div style="font-size:9px; color:rgba(255,255,255,0.5); margin-top:2px;">贴纸</div>
</div>
</div>
<div style="
padding:5px 16px; border-top:0.5px solid rgba(255,255,255,0.06);
display:flex; justify-content:space-between; align-items:center;
font-size:10px; color:rgba(255,255,255,0.3);
">
<span>🖼️ PNG · 1080×1920</span>
<span style="font-weight:600; letter-spacing:0.8px; color:rgba(255,255,255,0.5);">xycard 1.0</span>
<span>📍 ⏳</span>
</div>
<div style="width:134px; height:5px; margin:6px auto 8px; border-radius:3px; background:rgba(255,255,255,0.15);"></div>
</div>
<div style="
text-align:center; padding:8px; font-size:11px;
color:rgba(255,255,255,0.3);
">⚠️ 旧版:无滑动、无弧形、空白过多、工具箱挤占空间</div>
</div>
</div>
<script>
let currentPage = 0;
const totalPages = 3;
let touchStartX = 0;
let touchStartY = 0;
let isDragging = false;
const container = document.getElementById('pagesContainer');
function goPage(idx) {
if (idx < 0 || idx >= totalPages) return;
const oldPage = currentPage;
currentPage = idx;
for (let i = 0; i < totalPages; i++) {
const page = document.getElementById('page' + i);
page.className = 'tool-page';
if (i < idx) page.classList.add('left');
else if (i === idx) page.classList.add('center');
else page.classList.add('right');
}
document.querySelectorAll('.page-dot').forEach((d, i) => {
d.classList.toggle('active', i === idx);
});
updateIndicator();
if (oldPage !== idx) {
triggerArcDeform();
}
}
function updateIndicator() {
const page = document.getElementById('page' + currentPage);
const activeBtn = page.querySelector('.tool-btn.active');
const indicator = document.getElementById('indicator');
const container = document.getElementById('pagesContainer');
if (!activeBtn || !indicator || !container) return;
const btnRect = activeBtn.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const left = btnRect.left - containerRect.left - 4;
const width = btnRect.width + 8;
indicator.style.left = left + 'px';
indicator.style.width = width + 'px';
indicator.style.top = '10px';
}
function tapTool(el, pageIdx, btnIdx) {
const page = document.getElementById('page' + pageIdx);
page.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active'));
el.classList.add('active');
el.classList.add('slide-deform');
setTimeout(() => el.classList.remove('slide-deform'), 500);
updateIndicator();
}
function tapToolbox() {
const btn = document.querySelector('.arc-toolbox-btn');
btn.style.transform = 'translateX(-50%) scale(0.85)';
setTimeout(() => {
btn.style.transform = 'translateX(-50%) scale(1.1)';
setTimeout(() => {
btn.style.transform = 'translateX(-50%) scale(1)';
}, 150);
}, 100);
}
function triggerArcDeform() {
const page = document.getElementById('page' + currentPage);
const btns = page.querySelectorAll('.tool-btn');
btns.forEach((btn, i) => {
setTimeout(() => {
btn.classList.add('deforming');
setTimeout(() => btn.classList.remove('deforming'), 450);
}, i * 50);
});
}
function togglePanel(el) {
el.classList.toggle('active');
}
function toggleDebug() {
const debugBtn = document.querySelector('.debug-btn');
debugBtn.style.opacity = debugBtn.style.opacity === '1' ? '0.4' : '1';
}
function switchView(view) {
document.querySelectorAll('.scheme-tab').forEach(t => t.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('mainView').style.display = view === 'main' ? '' : 'none';
document.getElementById('compareView').style.display = view === 'compare' ? '' : 'none';
document.getElementById('descCard').style.display = view === 'main' ? '' : 'none';
}
// Touch handling for swipe
container.addEventListener('touchstart', e => {
touchStartX = e.changedTouches[0].clientX;
touchStartY = e.changedTouches[0].clientY;
isDragging = true;
}, { passive: true });
container.addEventListener('touchmove', e => {
if (!isDragging) return;
const dx = e.changedTouches[0].clientX - touchStartX;
const dy = e.changedTouches[0].clientY - touchStartY;
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 10) {
e.preventDefault();
}
}, { passive: false });
container.addEventListener('touchend', e => {
if (!isDragging) return;
isDragging = false;
const dx = e.changedTouches[0].clientX - touchStartX;
if (Math.abs(dx) > 40) {
if (dx < 0 && currentPage < totalPages - 1) goPage(currentPage + 1);
else if (dx > 0 && currentPage > 0) goPage(currentPage - 1);
}
}, { passive: true });
// Mouse drag for desktop
let mouseDown = false;
let mouseStartX = 0;
container.addEventListener('mousedown', e => {
mouseDown = true;
mouseStartX = e.clientX;
});
window.addEventListener('mouseup', e => {
if (!mouseDown) return;
mouseDown = false;
const dx = e.clientX - mouseStartX;
if (Math.abs(dx) > 40) {
if (dx < 0 && currentPage < totalPages - 1) goPage(currentPage + 1);
else if (dx > 0 && currentPage > 0) goPage(currentPage - 1);
}
});
// Initial indicator position
setTimeout(updateIndicator, 100);
window.addEventListener('resize', updateIndicator);
// Auto-hide hint
setTimeout(() => {
const hint = document.getElementById('hint');
if (hint) {
hint.style.opacity = '0';
setTimeout(() => hint.style.display = 'none', 500);
}
}, 4000);
</script>
</body>
</html>