feat: 添加预览效果页面并优化交互效果

refactor: 优化代码健壮性和类型安全

style: 更新字体样式和全局CSS

fix: 修复IntersectionObserver潜在空引用问题

chore: 更新依赖和ESLint配置

build: 更新构建ID和路由配置
This commit is contained in:
张翔
2026-02-24 10:24:05 +08:00
parent 64165c4499
commit fecbfd1990
239 changed files with 3403 additions and 5181 deletions
+8 -8
View File
@@ -342,7 +342,7 @@ export function CountUp({ end, duration = 2000, delay = 0, prefix = '', suffix =
const hasAnimated = useRef(false);
useEffect(() => {
if (!isInView || hasAnimated.current) return;
if (!isInView || hasAnimated.current) {return;}
hasAnimated.current = true;
@@ -398,12 +398,12 @@ interface TypewriterProps {
export function Typewriter({ text, delay = 0, speed = 50, className = '', cursorClassName = '' }: TypewriterProps) {
const [displayText, setDisplayText] = useState('');
const [isTyping, setIsTyping] = useState(false);
const [_isTyping, setIsTyping] = useState(false);
const ref = useRef<HTMLSpanElement>(null);
const isInView = useInView(ref, { once: true });
useEffect(() => {
if (!isInView) return;
if (!isInView) {return;}
const startTyping = setTimeout(() => {
setIsTyping(true);
@@ -605,13 +605,13 @@ export function SplitText({ text, className = '', delay = 0, staggerDelay = 0.03
initial="hidden"
animate={isInView ? 'visible' : 'hidden'}
className={className}
style={{ display: 'inline-block' }}
style={{ display: 'inline-block', fontFamily: 'inherit' }}
>
{text.split('').map((char, index) => (
<motion.span
key={index}
variants={child}
style={{ display: 'inline-block' }}
style={{ display: 'inline-block', fontFamily: 'inherit' }}
>
{char === ' ' ? '\u00A0' : char}
</motion.span>
@@ -659,7 +659,7 @@ export function MagneticButton({ children, className = '', strength = 0.3, onCli
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
if (!ref.current) {return;}
const rect = ref.current.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
@@ -886,13 +886,13 @@ export function CounterWithEffect({
effect = 'bounce'
}: CounterWithEffectProps) {
const [count, setCount] = useState(0);
const [prevCount, setPrevCount] = useState(0);
const [_prevCount, setPrevCount] = useState(0);
const ref = useRef<HTMLSpanElement>(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
const hasAnimated = useRef(false);
useEffect(() => {
if (!isInView || hasAnimated.current) return;
if (!isInView || hasAnimated.current) {return;}
hasAnimated.current = true;
const startTime = Date.now();
+1 -1
View File
@@ -1,7 +1,7 @@
// Company Information
export const COMPANY_INFO = {
name: '四川睿新致远科技有限公司',
shortName: '睿新致',
shortName: '睿新致',
slogan: '专注科技创新,驱动智慧未来',
description: '专注于信息技术服务与解决方案,为企业提供全方位的数字化转型支持',
founded: '2026',
+1 -1
View File
@@ -38,5 +38,5 @@ export function escapeHTML(str: string): string {
'/': '&#x2F;',
};
return str.replace(/[&<>"'/]/g, (char) => map[char]);
return str.replace(/[&<>"'/]/g, (char) => map[char] ?? char);
}
+1 -1
View File
@@ -22,7 +22,7 @@ export function debounce<T extends (...args: unknown[]) => unknown>(
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout | null = null
return (...args: Parameters<T>) => {
if (timeout) clearTimeout(timeout)
if (timeout) {clearTimeout(timeout)}
timeout = setTimeout(() => func(...args), wait)
}
}