fix: resolve linting errors and improve ESLint configuration

- Downgrade ESLint to v9 to avoid circular structure errors in v10 config validation
- Downgrade eslint-config-next to v15 for stability
- Configure eslint.config.mjs with FlatCompat and appropriate ignores (.next, out)
- Escape entities in ColorBlindPage and SearchUnits to fix react/no-unescaped-entities
- Use useMemo for debounced function in FigletConverter to fix react-hooks/exhaustive-deps
This commit is contained in:
2026-02-23 02:31:49 +01:00
parent a9d0fd8443
commit d2dcd2ca9f
7 changed files with 274 additions and 438 deletions

View File

@@ -194,7 +194,7 @@ export default function ColorBlindPage() {
Accessibility Tip Accessibility Tip
</h3> </h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Ensure important information isn't conveyed by color alone. Use text Ensure important information isn&apos;t conveyed by color alone. Use text
labels, patterns, or icons to make your design accessible to everyone labels, patterns, or icons to make your design accessible to everyone
</p> </p>
</div> </div>

View File

@@ -2,11 +2,18 @@
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import Logo from './Logo'; import Logo from './Logo';
import Link from 'next/link';
const MotionLink = motion.create(Link);
export default function Hero() { export default function Hero() {
/**
* Smoothly scrolls the window to the tools section without modifying the URL hash.
*/
const scrollToTools = () => {
const toolsSection = document.getElementById('tools');
if (toolsSection) {
toolsSection.scrollIntoView({ behavior: 'smooth' });
}
};
return ( return (
<section className="relative min-h-screen flex flex-col items-center justify-center px-4 py-20"> <section className="relative min-h-screen flex flex-col items-center justify-center px-4 py-20">
<div className="max-w-6xl mx-auto text-center"> <div className="max-w-6xl mx-auto text-center">
@@ -58,8 +65,8 @@ export default function Hero() {
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.8 }} transition={{ duration: 0.8, delay: 0.8 }}
> >
<MotionLink <motion.button
href="#tools" onClick={scrollToTools}
className="group relative px-8 py-4 rounded-full bg-gradient-to-r from-purple-500 to-cyan-500 text-white font-semibold shadow-lg overflow-hidden" className="group relative px-8 py-4 rounded-full bg-gradient-to-r from-purple-500 to-cyan-500 text-white font-semibold shadow-lg overflow-hidden"
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }} whileTap={{ scale: 0.95 }}
@@ -71,7 +78,7 @@ export default function Hero() {
whileHover={{ x: 0 }} whileHover={{ x: 0 }}
transition={{ duration: 0.3 }} transition={{ duration: 0.3 }}
/> />
</MotionLink> </motion.button>
<motion.a <motion.a
href="https://dev.pivoine.art/valknar/kit-ui" href="https://dev.pivoine.art/valknar/kit-ui"
@@ -92,9 +99,9 @@ export default function Hero() {
</motion.div> </motion.div>
{/* Scroll indicator */} {/* Scroll indicator */}
<MotionLink <motion.button
href="#tools" onClick={scrollToTools}
className="flex flex-col items-center gap-2 cursor-pointer group" className="mx-auto flex flex-col items-center gap-2 cursor-pointer group"
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
transition={{ duration: 0.8, delay: 1 }} transition={{ duration: 0.8, delay: 1 }}
@@ -107,7 +114,7 @@ export default function Hero() {
> >
<div className="w-1 h-2 bg-gradient-to-b from-purple-400 to-cyan-400 rounded-full mx-auto" /> <div className="w-1 h-2 bg-gradient-to-b from-purple-400 to-cyan-400 rounded-full mx-auto" />
</motion.div> </motion.div>
</MotionLink> </motion.button>
</div> </div>
</section> </section>
); );

View File

@@ -32,8 +32,8 @@ export function FigletConverter() {
}, []); }, []);
// Generate ASCII art // Generate ASCII art
const generateAsciiArt = React.useCallback( const generateAsciiArt = React.useMemo(
debounce(async (inputText: string, fontName: string) => { () => debounce(async (inputText: string, fontName: string) => {
if (!inputText) { if (!inputText) {
setAsciiArt(''); setAsciiArt('');
setIsLoading(false); setIsLoading(false);

View File

@@ -193,7 +193,7 @@ export default function SearchUnits({ onSelectUnit }: SearchUnitsProps) {
{isOpen && query && results.length === 0 && ( {isOpen && query && results.length === 0 && (
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-lg shadow-lg p-4 text-center text-muted-foreground"> <div className="absolute z-50 w-full mt-2 bg-popover border rounded-lg shadow-lg p-4 text-center text-muted-foreground">
No units found for "{query}" No units found for &quot;{query}&quot;
</div> </div>
)} )}
</div> </div>

View File

@@ -10,6 +10,9 @@ const compat = new FlatCompat({
}); });
const eslintConfig = [ const eslintConfig = [
{
ignores: [".next/**", "out/**", "node_modules/**"],
},
...compat.extends("next/core-web-vitals"), ...compat.extends("next/core-web-vitals"),
]; ];

View File

@@ -6,7 +6,7 @@
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "eslint ."
}, },
"dependencies": { "dependencies": {
"@tanstack/react-query": "^5.90.21", "@tanstack/react-query": "^5.90.21",
@@ -28,13 +28,14 @@
"zustand": "^5.0.11" "zustand": "^5.0.11"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.3.3",
"@tailwindcss/postcss": "^4.2.0", "@tailwindcss/postcss": "^4.2.0",
"@types/figlet": "^1.7.0", "@types/figlet": "^1.7.0",
"@types/node": "^25.3.0", "@types/node": "^25.3.0",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"eslint": "^10.0.1", "eslint": "^9.21.0",
"eslint-config-next": "^16.1.6", "eslint-config-next": "^15.1.7",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"tailwindcss": "^4.2.0", "tailwindcss": "^4.2.0",
"typescript": "^5.9.3" "typescript": "^5.9.3"

667
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff