diff --git a/src/views/Home.vue b/src/views/Home.vue index 3b39383..5908ee5 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -499,10 +499,94 @@ export default defineComponent({ }); }; + const animate = (ctx: CanvasRenderingContext2D, snowflakes: any[], canvas: HTMLCanvasElement, maxFlakes: number) => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + if (snowflakes.length < maxFlakes && Math.random() < 0.05) { + snowflakes.push({ + x: Math.random() * canvas.width, + y: 0, + radius: Math.random() * 7 + 3, + speed: Math.random() * 0.5 + 0.3, + opacity: Math.random() * 0.6 + 0.4 + }); + } + snowflakes.forEach(flake => { + ctx.save(); + ctx.beginPath(); + for (let i = 0; i < 6; i++) { + ctx.moveTo(flake.x, flake.y); + ctx.lineTo( + flake.x + Math.cos(Math.PI * 2 * i / 6) * flake.radius, + flake.y + Math.sin(Math.PI * 2 * i / 6) * flake.radius + ); + } + ctx.strokeStyle = `rgba(255, 255, 255, ${flake.opacity})`; + ctx.lineWidth = 1.5; + ctx.stroke(); + ctx.restore(); + flake.x += Math.sin(flake.y / 50) * 0.3; + flake.y += flake.speed * 0.5; + if (flake.y > canvas.height) { + flake.y = 0; + flake.x = Math.random() * canvas.width; + } + }); + requestAnimationFrame(() => animate(ctx, snowflakes, canvas, maxFlakes)); + }; + onMounted(() => { handleScrollAnimations(); handleActiveSection(); window.addEventListener('scroll', handleScrollAnimations); + + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { + return; + } + if (new Date().getMonth() === 11 && new Date().getDate() >= 23 && new Date().getDate() <= 31) { + const wrapper = document.createElement('div'); + wrapper.classList.add('snow'); + wrapper.style.position = 'fixed'; + wrapper.style.top = '0'; + wrapper.style.left = '0'; + wrapper.style.width = '100%'; + wrapper.style.height = '100px'; + wrapper.style.pointerEvents = 'none'; + wrapper.style.zIndex = '9999'; + wrapper.style.maskImage = 'linear-gradient(to top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) 35px)'; + wrapper.style.transition = 'opacity 0.3s ease-in-out'; + const canvas = document.createElement('canvas'); + canvas.style.width = '100%'; + canvas.style.height = '100%'; + canvas.width = window.innerWidth * 2; + canvas.height = 200; + wrapper.appendChild(canvas); + document.body.appendChild(wrapper); + const ctx = canvas.getContext('2d'); + const snowflakes: any[] = []; + const getMaxFlakes = () => { + return window.innerWidth <= 800 ? 25 : 50; + }; + let maxFlakes = getMaxFlakes(); + if (ctx) { + animate(ctx, snowflakes, canvas, maxFlakes); + } + window.addEventListener('resize', () => { + canvas.width = window.innerWidth * 2; + canvas.height = 200; + maxFlakes = getMaxFlakes(); + if (snowflakes.length > maxFlakes) { + snowflakes.length = maxFlakes; + } + }); + window.addEventListener('scroll', () => { + const scrollTop = window.scrollY || document.documentElement.scrollTop; + if (scrollTop > 100) { + wrapper.style.opacity = Math.max(0, 1 - (scrollTop - 100) / 200).toString(); + } else { + wrapper.style.opacity = '1'; + } + }); + } }); onUnmounted(() => {