feat: 更新 ESLint 和 Prettier 配置,增强代码质量管理

- 在 .gitignore 中添加 public/audio/* 以忽略音频文件。
- 更新 bun.lock,添加 eslint-config-prettier 和 eslint-plugin-prettier 依赖,确保 ESLint 与 Prettier 的兼容性。
- 修改 eslint.config.ts,整合 Prettier 规则,优化代码风格一致性。
- 在 package.json 中添加 lint:fix 和 format 脚本,简化代码格式化和修复流程。
- 更新 tailwind.config.ts 和其他组件文件,统一代码风格,提升可读性。
This commit is contained in:
zhongyidian committed 2026-03-05 13:50:47 +08:00
1 parent 5d00adc1a5
commit 76c67b492e
216 files changed
+12454 -13976

No files matched your search

+47 -51
View File
@@ -1,16 +1,16 @@
import { useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
import type { ImageProps } from "./image.types";
import { useState, useRef, useEffect } from 'react'
import { cn } from '@/lib/utils'
import type { ImageProps } from './image.types'
export function Image({
src,
alt = "",
alt = '',
className,
width,
height,
objectFit = "cover",
objectPosition = "center",
loading = "lazy",
objectFit = 'cover',
objectPosition = 'center',
loading = 'lazy',
placeholder,
fallback,
onLoad,
@@ -21,81 +21,77 @@ export function Image({
style,
...restProps
}: ImageProps) {
const [imageSrc, setImageSrc] = useState(src);
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
const imgRef = useRef<HTMLImageElement>(null);
const [imageSrc, setImageSrc] = useState(src)
const [isLoading, setIsLoading] = useState(true)
const [hasError, setHasError] = useState(false)
const [isLoaded, setIsLoaded] = useState(false)
const imgRef = useRef<HTMLImageElement>(null)
// 处理图片加载
const handleLoad = () => {
setIsLoading(false);
setIsLoaded(true);
setHasError(false);
onLoad?.();
};
setIsLoading(false)
setIsLoaded(true)
setHasError(false)
onLoad?.()
}
// 处理图片错误
const handleError = () => {
setIsLoading(false);
setHasError(true);
setIsLoading(false)
setHasError(true)
if (fallback && imageSrc !== fallback) {
setImageSrc(fallback);
setImageSrc(fallback)
}
onError?.();
};
onError?.()
}
// 重置状态当src改变时
useEffect(() => {
if (src !== imageSrc) {
setImageSrc(src);
setIsLoading(true);
setHasError(false);
setIsLoaded(false);
setImageSrc(src)
setIsLoading(true)
setHasError(false)
setIsLoaded(false)
}
}, [src, imageSrc]);
}, [src, imageSrc])
// 懒加载处理
useEffect(() => {
if (
loading === "lazy" &&
typeof IntersectionObserver !== "undefined" &&
imgRef.current
) {
if (loading === 'lazy' && typeof IntersectionObserver !== 'undefined' && imgRef.current) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setImageSrc(src);
observer.disconnect();
setImageSrc(src)
observer.disconnect()
}
});
})
},
{ threshold: 0.1 }
);
)
observer.observe(imgRef.current);
return () => observer.disconnect();
observer.observe(imgRef.current)
return () => observer.disconnect()
}
}, [loading, src]);
}, [loading, src])
const imageStyle: React.CSSProperties = {
width,
height,
objectFit,
objectPosition,
filter: blur ? "blur(4px)" : "none",
transition: "filter 0.3s ease",
filter: blur ? 'blur(4px)' : 'none',
transition: 'filter 0.3s ease',
...style,
};
}
return (
<div
className={cn(
"relative",
width === "100%" ? "block" : "inline-block",
'relative',
width === '100%' ? 'block' : 'inline-block',
button &&
"cursor-pointer transition-all duration-300 hover:scale-105 hover:brightness-110 hover:contrast-110 active:scale-95",
'cursor-pointer transition-all duration-300 hover:scale-105 hover:brightness-110 hover:contrast-110 active:scale-95',
className
)}
style={{ width, height }}
@@ -107,8 +103,8 @@ export function Image({
className="w-full h-full bg-gray-200 flex items-center justify-center"
style={{
backgroundImage: `url(${placeholder})`,
backgroundSize: "cover",
backgroundPosition: "center",
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
>
<div className="animate-pulse bg-gray-300 rounded w-full h-full" />
@@ -155,11 +151,11 @@ export function Image({
onLoad={handleLoad}
onError={handleError}
className={cn(
"transition-opacity duration-300",
isLoaded ? "opacity-100" : "opacity-0",
"w-full h-full"
'transition-opacity duration-300',
isLoaded ? 'opacity-100' : 'opacity-0',
'w-full h-full'
)}
/>
</div>
);
)
}
+17 -17
View File
@@ -1,36 +1,36 @@
import type { HTMLAttributes } from "react";
import type { HTMLAttributes } from 'react'
export interface ImageProps extends HTMLAttributes<HTMLDivElement> {
/** 图片地址 */
src: string;
src: string
/** 图片替代文本 */
alt?: string;
alt?: string
/** 自定义类名 */
className?: string;
className?: string
/** 图片宽度 */
width?: number | string;
width?: number | string
/** 图片高度 */
height?: number | string;
height?: number | string
/** 图片填充方式 */
objectFit?: "cover" | "contain" | "fill" | "none" | "scale-down";
objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
/** 图片位置 */
objectPosition?: string;
objectPosition?: string
/** 加载方式 */
loading?: "lazy" | "eager";
loading?: 'lazy' | 'eager'
/** 占位图 */
placeholder?: string;
placeholder?: string
/** 加载失败时的回退图片 */
fallback?: string;
fallback?: string
/** 图片加载完成回调 */
onLoad?: () => void;
onLoad?: () => void
/** 图片加载失败回调 */
onError?: () => void;
onError?: () => void
/** 是否可拖拽 */
draggable?: boolean;
draggable?: boolean
/** 模糊效果 */
blur?: boolean;
blur?: boolean
/** 图片质量(仅用于提示) */
quality?: number;
quality?: number
/** 是否启用按钮样式(hover 和 active 效果) */
button?: boolean;
button?: boolean
}
+2 -2
View File
@@ -1,2 +1,2 @@
export * from "./image";
export * from "./image.types";
export * from './image'
export * from './image.types'