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

+114 -120
View File
@@ -1,51 +1,50 @@
import { useMemo, useState } from "react";
import { getBackgroundImage, getStaticImage } from "@/lib/utils";
import { usePuzzleStore } from "@/store/puzzleStore";
import { Image } from "@/components";
import { useMemo, useState } from 'react'
import { getBackgroundImage, getStaticImage } from '@/lib/utils'
import { usePuzzleStore } from '@/store/puzzleStore'
import { Image } from '@/components'
/**
* 六边形进度条组件
* 根据进度值显示不同颜色:100%绿色,50%-99%橙色,0%-49%灰色
*/
interface HexagonProgressBarProps {
progress: number; // 0-100
progress: number // 0-100
}
const HexagonProgressBar = ({ progress }: HexagonProgressBarProps) => {
const progressPercent = Math.min(100, Math.max(0, progress));
const progressText = progressPercent.toFixed(2) === "100.00"
? "进度100%"
: `进度${Math.round(progressPercent)}%`;
const progressPercent = Math.min(100, Math.max(0, progress))
const progressText =
progressPercent.toFixed(2) === '100.00' ? '进度100%' : `进度${Math.round(progressPercent)}%`
// 根据进度值确定填充颜色
const getProgressColor = () => {
if (progressPercent >= 100) {
return "#90B86B"; // 浅橄榄绿色(100%完成)
return '#90B86B' // 浅橄榄绿色(100%完成)
} else if (progressPercent >= 50) {
return "#EEB362"; // 橙色(50%-99%)
return '#EEB362' // 橙色(50%-99%)
} else {
return "#E0E0E0"; // 浅灰色(0%-49%)
return '#E0E0E0' // 浅灰色(0%-49%)
}
};
}
const fillColor = getProgressColor();
const fillColor = getProgressColor()
// 六边形路径,细长的水平六边形,左右两端是尖角
// 正确的六边形路径:从左顶点开始,顺时针绘制
// 左顶点(0%, 50%) -> 左上角(3%, 0%) -> 右上角(97%, 0%) -> 右顶点(100%, 50%) -> 右下角(97%, 100%) -> 左下角(3%, 100%)
// 外层路径(包含边框)
const outerHexagonPath = "polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)";
const outerHexagonPath = 'polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)'
// 内层路径(边框内部)
const innerHexagonPath = "polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)";
const borderWidth = 4; // 增加边框宽度从2px到3px
const innerHexagonPath = 'polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)'
const borderWidth = 4 // 增加边框宽度从2px到3px
return (
<div className="relative" style={{ width: "260px", height: "50px" }}>
<div className="relative" style={{ width: '260px', height: '50px' }}>
{/* 外层:白色边框(使用 clip-path 裁剪形状) */}
<div
className="absolute inset-0"
style={{
clipPath: outerHexagonPath,
backgroundColor: "white",
backgroundColor: 'white',
}}
/>
{/* 内容容器(边框内部区域) */}
@@ -63,7 +62,7 @@ const HexagonProgressBar = ({ progress }: HexagonProgressBarProps) => {
<div
className="absolute inset-0"
style={{
backgroundColor: "#757575",
backgroundColor: '#757575',
}}
/>
{/* 填充层(根据进度百分比从左侧填充) */}
@@ -78,7 +77,7 @@ const HexagonProgressBar = ({ progress }: HexagonProgressBarProps) => {
className="absolute inset-0"
style={{
backgroundColor: fillColor,
transition: "width 0.3s ease, background-color 0.3s ease",
transition: 'width 0.3s ease, background-color 0.3s ease',
}}
/>
</div>
@@ -88,42 +87,42 @@ const HexagonProgressBar = ({ progress }: HexagonProgressBarProps) => {
<div
className="absolute inset-0 flex items-center justify-center text-white text-2xl font-bold pointer-events-none"
style={{
textShadow: "0 2px 4px rgba(0,0,0,0.6), 0 1px 2px rgba(0,0,0,0.8)",
textShadow: '0 2px 4px rgba(0,0,0,0.6), 0 1px 2px rgba(0,0,0,0.8)',
zIndex: 10,
}}
>
{progressText}
</div>
</div>
);
};
)
}
export interface MenuPuzzleCenterProps {
/** 是否可见 */
visible: boolean;
visible: boolean
/** 关闭回调 */
onClose: () => void;
onClose: () => void
/** 选择某个故居后的回调(进入对应的碎片系统) */
onSelectResidence: (residence: string) => void;
onSelectResidence: (residence: string) => void
}
interface ResidenceConfig {
/** 拼图存储用的英文 key(如 chenyun) */
residence: string;
residence: string
/** 显示名称 */
displayName: string;
displayName: string
/** 在大地图上的水平位置(百分比字符串,如 "20%") */
left: string;
left: string
/** 在大地图上的垂直位置(百分比字符串,如 "40%") */
top: string;
top: string
/** 显示用图片路径(相对于 puzzle/home/ 目录) */
image: string;
image: string
/** 是否已经开放拼图(未开放时只展示,不可点击) */
hasPuzzle: boolean;
hasPuzzle: boolean
/** 是否有导图资源 */
hasMap?: boolean;
hasMap?: boolean
/** 导图资源文件名(位于 puzzle/home/map 下) */
mapImage?: string;
mapImage?: string
}
/**
@@ -133,91 +132,87 @@ interface ResidenceConfig {
*/
const RESIDENCE_LIST: ResidenceConfig[] = [
{
residence: "maozedong",
displayName: "毛泽东旧居",
left: "30%",
top: "35%",
image: "毛泽东",
residence: 'maozedong',
displayName: '毛泽东旧居',
left: '30%',
top: '35%',
image: '毛泽东',
hasPuzzle: true,
hasMap: true,
mapImage: "毛泽东导图",
mapImage: '毛泽东导图',
},
{
residence: "sunzhongshan",
displayName: "孙中山故居",
left: "12%",
top: "51%",
image: "孙中山",
residence: 'sunzhongshan',
displayName: '孙中山故居',
left: '12%',
top: '51%',
image: '孙中山',
hasPuzzle: true,
hasMap: true,
mapImage: "孙中山导图",
mapImage: '孙中山导图',
},
{
residence: "luxun",
displayName: "鲁迅故居",
left: "26.3%",
top: "74%",
image: "鲁迅",
residence: 'luxun',
displayName: '鲁迅故居',
left: '26.3%',
top: '74%',
image: '鲁迅',
hasPuzzle: true,
hasMap: true,
mapImage: "鲁迅导图",
mapImage: '鲁迅导图',
},
{
residence: "huangyanpei",
displayName: "黄炎培故居",
left: "44%",
top: "67%",
image: "黄炎培",
residence: 'huangyanpei',
displayName: '黄炎培故居',
left: '44%',
top: '67%',
image: '黄炎培',
hasPuzzle: true,
hasMap: true,
mapImage: "黄炎培导图",
mapImage: '黄炎培导图',
},
{
residence: "nieer",
displayName: "聂耳旧居",
left: "62%",
top: "60%",
image: "聂耳",
residence: 'nieer',
displayName: '聂耳旧居',
left: '62%',
top: '60%',
image: '聂耳',
hasPuzzle: true,
hasMap: false,
},
{
residence: "zhangleping",
displayName: "张乐平故居",
left: "73%",
top: "33%",
image: "张乐平",
residence: 'zhangleping',
displayName: '张乐平故居',
left: '73%',
top: '33%',
image: '张乐平',
hasPuzzle: true,
hasMap: false,
},
{
residence: "rongdesheng",
displayName: "荣德生旧居",
left: "90%",
top: "45%",
image: "荣德生",
residence: 'rongdesheng',
displayName: '荣德生旧居',
left: '90%',
top: '45%',
image: '荣德生',
hasPuzzle: true,
hasMap: false,
},
{
residence: "chenyun",
displayName: "陈云故居",
left: "80%",
top: "76%",
image: "陈云",
residence: 'chenyun',
displayName: '陈云故居',
left: '80%',
top: '76%',
image: '陈云',
hasPuzzle: true,
hasMap: true,
mapImage: "陈云导图",
mapImage: '陈云导图',
},
];
]
const MenuPuzzleCenter = ({
visible,
onClose,
onSelectResidence,
}: MenuPuzzleCenterProps) => {
const { getPuzzleCollectProgress } = usePuzzleStore();
const [activeMapImage, setActiveMapImage] = useState<string | null>(null);
const MenuPuzzleCenter = ({ visible, onClose, onSelectResidence }: MenuPuzzleCenterProps) => {
const { getPuzzleCollectProgress } = usePuzzleStore()
const [activeMapImage, setActiveMapImage] = useState<string | null>(null)
const residenceProgress = useMemo(
() =>
@@ -227,37 +222,40 @@ const MenuPuzzleCenter = ({
progress: item.hasPuzzle ? getPuzzleCollectProgress(item.residence) : 0,
})),
[getPuzzleCollectProgress]
);
)
if (!visible) return null;
if (!visible) return null
return (
<div
className="fixed inset-0 z-90 flex items-center justify-center"
style={{ background: "rgba(0,0,0,0.8)" }}
style={{ background: 'rgba(0,0,0,0.8)' }}
onClick={(e) => {
if (e.target === e.currentTarget) {
onClose();
onClose()
}
}}
>
<div
className="relative w-full h-full bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: getBackgroundImage("puzzle/home/底图") }}
style={{ backgroundImage: getBackgroundImage('puzzle/home/底图') }}
>
{/* 箭头指示底图 */}
<img className="absolute top-84 left-55" src={getStaticImage("puzzle/home/箭头指引")} alt="" />
<img
className="absolute top-84 left-55"
src={getStaticImage('puzzle/home/箭头指引')}
alt=""
/>
{/* 关闭按钮 */}
<Image
className="absolute right-8 top-8 z-10"
src={getStaticImage("components/关闭")}
src={getStaticImage('components/关闭')}
alt="关闭"
button
onClick={onClose}
/>
{/* 故居列表:按照设计图进行绝对定位 */}
<div className="absolute inset-0">
{residenceProgress.map(
@@ -278,10 +276,7 @@ const MenuPuzzleCenter = ({
style={{ left, top }}
>
{/* 故居图片(资源在 puzzle/home 下,可根据实际名称调整) */}
<Image
src={getStaticImage(`puzzle/home/${image}`)}
alt={displayName}
/>
<Image src={getStaticImage(`puzzle/home/${image}`)} alt={displayName} />
{/* 进度展示,仅对已开放拼图的故居显示 */}
{hasPuzzle && (
@@ -292,20 +287,24 @@ const MenuPuzzleCenter = ({
{/* 图标 */}
<div className="flex justify-center gap-6">
<Image src={getStaticImage(`puzzle/home/拼图`)} alt="拼图" button
<Image
src={getStaticImage(`puzzle/home/拼图`)}
alt="拼图"
button
onClick={(e) => {
if (!hasPuzzle) return;
e.stopPropagation();
onSelectResidence(residence);
}} />
if (!hasPuzzle) return
e.stopPropagation()
onSelectResidence(residence)
}}
/>
<Image
src={getStaticImage(`puzzle/home/导图`)}
alt="导图"
button
onClick={(e) => {
e.stopPropagation();
if (!hasMap || !mapImage) return;
setActiveMapImage(mapImage);
e.stopPropagation()
if (!hasMap || !mapImage) return
setActiveMapImage(mapImage)
}}
/>
</div>
@@ -318,10 +317,10 @@ const MenuPuzzleCenter = ({
{activeMapImage && (
<div
className="fixed inset-0 z-110 flex items-center justify-center"
style={{ background: "rgba(0,0,0,0.75)" }}
style={{ background: 'rgba(0,0,0,0.75)' }}
onClick={(e) => {
if (e.target === e.currentTarget) {
setActiveMapImage(null);
setActiveMapImage(null)
}
}}
>
@@ -329,25 +328,20 @@ const MenuPuzzleCenter = ({
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<Image
className="absolute -right-4 -top-8 z-10"
src={getStaticImage("components/close")}
src={getStaticImage('components/close')}
alt="关闭"
button
onClick={() => setActiveMapImage(null)}
/>
<img
src={getStaticImage(`puzzle/home/map/${activeMapImage}`)}
alt="导图"
/>
<img src={getStaticImage(`puzzle/home/map/${activeMapImage}`)} alt="导图" />
</div>
</div>
</div>
)}
</div>
</div>
);
};
export default MenuPuzzleCenter;
)
}
export default MenuPuzzleCenter