import { useEffect, useRef } from 'react'; import { Button, Container, Title, Text, Group, Stack } from '@mantine/core'; import { useNavigate } from 'react-router-dom'; import iconUrl from '../assets/icon.png'; // 禅意算法背景 - 手印静寂(循环墨晕效果) function ZenBackground() { const canvasRef = useRef(null); const animationRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; const resize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; resize(); window.addEventListener('resize', resize); const random = (min = 0, max = 1) => { return min + Math.random() * (max - min); }; const noise = (x: number, y: number, t: number) => { return (Math.sin(x * 0.01 + t) * Math.cos(y * 0.01 + t * 0.7) + 1) * 0.5; }; interface InkStroke { points: { x: number; y: number; weight: number }[]; x: number; y: number; angle: number; speed: number; inkAlpha: number; baseWeight: number; maxLength: number; currentLength: number; complete: boolean; } let strokes: InkStroke[] = []; let time = 0; let lastStrokeTime = 0; const strokeInterval = 30; const createStroke = (): InkStroke | null => { const angle = random(0, Math.PI * 2); const radius = random(canvas.width * 0.1, canvas.width * 0.4); const x = canvas.width / 2 + Math.cos(angle) * radius; const y = canvas.height / 2 + Math.sin(angle) * radius; return { points: [{ x, y, weight: random(0.3, 1.5) }], x, y, angle: random(0, Math.PI * 2), speed: random(0.4, 1.0), inkAlpha: random(10, 30), baseWeight: random(0.3, 1.5), maxLength: random(30, 90), currentLength: 0, complete: false, }; }; const initStrokes = () => { strokes = []; for (let i = 0; i < 8; i++) { const stroke = createStroke(); if (stroke) { stroke.currentLength = random(0, stroke.maxLength * 0.5); strokes.push(stroke); } } }; initStrokes(); ctx.fillStyle = '#faf9f7'; ctx.fillRect(0, 0, canvas.width, canvas.height); const animate = () => { time += 0.008; if (Math.floor(time * 125) % 3 === 0) { ctx.fillStyle = 'rgba(250, 249, 247, 0.12)'; ctx.fillRect(0, 0, canvas.width, canvas.height); } if (time - lastStrokeTime > strokeInterval * 0.01) { lastStrokeTime = time; strokes = strokes.filter(s => !s.complete || s.currentLength < s.maxLength); const newCount = Math.floor(random(0, 2)); for (let i = 0; i < newCount; i++) { const stroke = createStroke(); if (stroke) strokes.push(stroke!); } } for (const stroke of strokes) { if (stroke.complete) continue; const n = noise(stroke.x, stroke.y, time); stroke.angle += (n - 0.5) * 0.12; const breath = Math.sin(time * 1.5 + stroke.x * 0.01) * 0.25; const currentSpeed = stroke.speed * (1 + breath * 0.2); stroke.x += Math.cos(stroke.angle) * currentSpeed; stroke.y += Math.sin(stroke.angle) * currentSpeed; const progress = stroke.currentLength / stroke.maxLength; const weightVar = Math.sin(progress * Math.PI) * 1.0; const weight = Math.max(0.2, stroke.baseWeight + weightVar); stroke.points.push({ x: stroke.x, y: stroke.y, weight }); stroke.currentLength++; if ( stroke.currentLength >= stroke.maxLength || stroke.x < -50 || stroke.x > canvas.width + 50 || stroke.y < -50 || stroke.y > canvas.height + 50 ) { stroke.complete = true; } if (stroke.points.length > 1) { for (let i = 1; i < stroke.points.length; i++) { const p1 = stroke.points[i - 1]; const p2 = stroke.points[i]; const alpha = stroke.inkAlpha * (1 - i / stroke.points.length * 0.4) / 100; const size = p2.weight * random(0.8, 1.2); ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.strokeStyle = `rgba(25, 25, 25, ${alpha})`; ctx.lineWidth = size; ctx.lineCap = 'round'; ctx.stroke(); if (random(0, 1) < 0.3) { ctx.beginPath(); ctx.arc(p2.x, p2.y, size * random(0.5, 1.5), 0, Math.PI * 2); ctx.fillStyle = `rgba(25, 25, 25, ${alpha * 0.3})`; ctx.fill(); } } } } const centerX = canvas.width / 2; const centerY = canvas.height / 2; const breathScale = 1 + Math.sin(time * 0.3) * 0.015; const radius = Math.min(canvas.width, canvas.height) * 0.18 * breathScale; const gap = Math.PI * 0.18; const startAngle = -Math.PI / 2 + time * 0.05; ctx.beginPath(); for (let a = startAngle; a < startAngle + Math.PI * 2 - gap; a += 0.04) { const noiseOffset = noise(Math.cos(a) * 2, Math.sin(a) * 2, time * 0.2) * 5 - 2.5; const r = radius + noiseOffset; const x = centerX + Math.cos(a) * r; const y = centerY + Math.sin(a) * r; if (a === startAngle) { ctx.moveTo(x, y); } else { ctx.lineTo(x, y); } } ctx.strokeStyle = 'rgba(25, 25, 25, 0.06)'; ctx.lineWidth = 0.8; ctx.stroke(); animationRef.current = requestAnimationFrame(animate); }; animate(); return () => { window.removeEventListener('resize', resize); if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, []); return ( ); } export function LandingPage() { const navigate = useNavigate(); return (
{/* 装饰性圆相 */} {/* 产品图标 */}
掐日子
{/* 主标题 - 优化字体 */} 掐日子 {/* 副标题 - 增强可读性 */} AI 纪念日 · 提醒 {/* 描述文案 */} 轻便、灵活的倒数日和提醒应用
让每一个重要的日子都被铭记
纪念日 提醒 AI 便签
); }