From 82a2d231c3be217783ff6ab85ef254670999e895 Mon Sep 17 00:00:00 2001 From: Chen Gu Date: Fri, 24 Apr 2026 09:31:21 +0800 Subject: [PATCH] feat: story-journey immersive layer (progress, scene focus, floating orbs) --- themes/dreamscape/assets/css/dreamscape.css | 115 ++++++++++++++++++ themes/dreamscape/assets/js/dreamscape.js | 52 ++++++++ .../dreamscape/layouts/_default/baseof.html | 2 +- .../dreamscape/layouts/_default/single.html | 12 +- 4 files changed, 178 insertions(+), 3 deletions(-) diff --git a/themes/dreamscape/assets/css/dreamscape.css b/themes/dreamscape/assets/css/dreamscape.css index 3eb9a8d..f256ed3 100644 --- a/themes/dreamscape/assets/css/dreamscape.css +++ b/themes/dreamscape/assets/css/dreamscape.css @@ -253,6 +253,121 @@ main { font-family: var(--font-sans); } +/* ═══ 故事沉浸层(文章页) ═══ */ +.story-journey { + position: relative; + isolation: isolate; +} + +.story-orb { + position: fixed; + pointer-events: none; + z-index: -1; + border-radius: 50%; + filter: blur(36px); + opacity: 0.35; + mix-blend-mode: screen; + transition: transform 0.2s ease-out; +} + +.orb-1 { + width: 280px; + height: 280px; + top: 14%; + left: -80px; + background: radial-gradient(circle, rgba(123,104,238,0.42), transparent 70%); +} + +.orb-2 { + width: 220px; + height: 220px; + top: 48%; + right: -60px; + background: radial-gradient(circle, rgba(34,211,238,0.34), transparent 72%); +} + +.orb-3 { + width: 320px; + height: 320px; + bottom: 6%; + left: 24%; + background: radial-gradient(circle, rgba(74,144,217,0.30), transparent 72%); +} + +.story-progress { + position: sticky; + top: 62px; + height: 4px; + background: rgba(123,104,238,0.18); + border-radius: 999px; + overflow: hidden; + margin: -1rem 0 2rem; + z-index: 40; +} + +.story-progress-bar { + height: 100%; + width: 0%; + background: linear-gradient(90deg, var(--glow-purple), var(--glow-cyan)); + box-shadow: 0 0 18px rgba(123,104,238,0.6); + transition: width 0.08s linear; +} + +/* 场景段落:像旅程节点 */ +.article-body > p { + position: relative; + padding-left: 1.1rem; +} + +.article-body > p::before { + content: ''; + position: absolute; + left: -0.15rem; + top: 0.85rem; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--glow-purple); + box-shadow: 0 0 12px rgba(123,104,238,0.8); + opacity: 0.55; +} + +.article-body > p.active-scene::before { + background: var(--glow-cyan); + box-shadow: 0 0 16px rgba(34,211,238,0.9); + opacity: 1; +} + +.article-body > p.active-scene { + text-shadow: 0 0 18px rgba(123,104,238,0.22); +} + +/* 手机端沉浸优化 */ +@media (max-width: 640px) { + .story-progress { + top: 54px; + margin: -0.5rem 0 1.2rem; + } + .story-orb { + filter: blur(26px); + opacity: 0.28; + } + .orb-1 { width: 180px; height: 180px; left: -60px; } + .orb-2 { width: 150px; height: 150px; right: -45px; } + .orb-3 { width: 190px; height: 190px; left: 20%; } +} + +/* 降级策略:用户偏好减少动画 */ +@media (prefers-reduced-motion: reduce) { + .story-orb, + .story-progress-bar, + .reveal, + .js-ready .article-body p { + animation: none !important; + transition: none !important; + } +} + /* ═══ 文章页 ═══ */ .dream-article { padding-top: 2rem; diff --git a/themes/dreamscape/assets/js/dreamscape.js b/themes/dreamscape/assets/js/dreamscape.js index 0f4b7b0..b2be75c 100644 --- a/themes/dreamscape/assets/js/dreamscape.js +++ b/themes/dreamscape/assets/js/dreamscape.js @@ -7,6 +7,7 @@ // ═══ 星空粒子系统 ═══ const canvas = document.getElementById('starfield'); + if (!canvas) return; const ctx = canvas.getContext('2d'); let width, height, stars, nebulas; let animationId; @@ -133,6 +134,55 @@ }); } + // ═══ 场景滚动进度 + 旅程节点高亮 ═══ + function setupStoryJourney() { + const body = document.getElementById('storyBody'); + const progress = document.getElementById('storyProgress'); + if (!body || !progress) return; + + const scenes = Array.from(body.querySelectorAll(':scope > p')); + if (!scenes.length) return; + + const onScroll = () => { + const rect = body.getBoundingClientRect(); + const total = Math.max(body.scrollHeight - window.innerHeight, 1); + const scrolled = Math.min(Math.max(-rect.top, 0), total); + const ratio = scrolled / total; + progress.style.width = `${(ratio * 100).toFixed(2)}%`; + + let activeIndex = 0; + let minDistance = Infinity; + scenes.forEach((p, idx) => { + const r = p.getBoundingClientRect(); + const d = Math.abs(r.top - window.innerHeight * 0.35); + if (d < minDistance) { + minDistance = d; + activeIndex = idx; + } + }); + scenes.forEach((p, idx) => p.classList.toggle('active-scene', idx === activeIndex)); + }; + + window.addEventListener('scroll', onScroll, { passive: true }); + onScroll(); + } + + // ═══ 漂浮光团轻微视差 ═══ + function setupOrbsParallax() { + const orbs = document.querySelectorAll('.story-orb'); + if (!orbs.length) return; + + window.addEventListener('scroll', () => { + const y = window.scrollY; + orbs.forEach((orb, i) => { + const factor = (i + 1) * 0.04; + const xShift = Math.sin(y * 0.002 + i) * 10; + const yShift = y * factor; + orb.style.transform = `translate(${xShift}px, ${yShift}px)`; + }); + }, { passive: true }); + } + // ═══ 初始化 ═══ window.addEventListener('resize', () => { resize(); @@ -146,6 +196,8 @@ setupReveal(); setupParallax(); setupGlow(); + setupStoryJourney(); + setupOrbsParallax(); }); })(); diff --git a/themes/dreamscape/layouts/_default/baseof.html b/themes/dreamscape/layouts/_default/baseof.html index 7d3ab67..5d9e2fd 100644 --- a/themes/dreamscape/layouts/_default/baseof.html +++ b/themes/dreamscape/layouts/_default/baseof.html @@ -10,7 +10,7 @@ - +
-
+
+
+
+ +
{{ .Content }}