Enhances ESLint configuration and rules#106
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. 📝 WalkthroughPre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (6)
src/components/layout/home/hero/profile-image.tsx (1)
78-83: Refactor looks correct, but consider removing type assertions.The simplified compound conditions correctly preserve the original logic. However, the repeated
as AchievementIdtype assertions suggest these string literals are not properly typed. If'LADYBIRD_LANDING','CONFUSED_CLICK', and'GRUMPY_GLIMPSE'(lines 94, 110) are valid achievement IDs, consider defining them as const values with explicitAchievementIdtype or using an enum to eliminate the need for type assertions.Example refactor to centralize achievement IDs:
// In achievements.ts or a constants file export const ACHIEVEMENT_IDS = { LADYBIRD_LANDING: 'LADYBIRD_LANDING', CONFUSED_CLICK: 'CONFUSED_CLICK', GRUMPY_GLIMPSE: 'GRUMPY_GLIMPSE', } as const satisfies Record<string, AchievementId>Then use throughout the file:
- if (isLadybird && !has('LADYBIRD_LANDING' as AchievementId)) { - unlock('LADYBIRD_LANDING' as AchievementId) + if (isLadybird && !has(ACHIEVEMENT_IDS.LADYBIRD_LANDING)) { + unlock(ACHIEVEMENT_IDS.LADYBIRD_LANDING) } - if (useConfused && !has('CONFUSED_CLICK' as AchievementId)) { - unlock('CONFUSED_CLICK' as AchievementId) + if (useConfused && !has(ACHIEVEMENT_IDS.CONFUSED_CLICK)) { + unlock(ACHIEVEMENT_IDS.CONFUSED_CLICK) }src/hooks/use-leaderboard.ts (2)
125-126: Consider reverting tocharCodeAt/fromCharCodefor ASCII-only operations.The switch from
charCodeAt/fromCharCodetocodePointAt/fromCodePointadds complexity without benefit when handling single ASCII characters (A-Z). Both APIs are functionally identical for Basic Multilingual Plane characters. The?? 0fallback could produce invalid results (String.fromCodePoint(1)= '\x01') if the guard on line 124 fails, though that guard should be sufficient.If you prefer to keep the code point APIs for consistency with the broader codebase modernization, consider adding a type assertion or comment clarifying that these operations are guaranteed to be on ASCII characters:
- const newChar = currentChar === 'Z' ? 'A' : String.fromCodePoint((currentChar.codePointAt(0) ?? 0) + 1) + // Safe: currentChar is guaranteed to be A-Z by guard above + const newChar = currentChar === 'Z' ? 'A' : String.fromCodePoint(currentChar.codePointAt(0)! + 1)Alternatively, revert to the simpler ASCII-only APIs:
- const newChar = currentChar === 'Z' ? 'A' : String.fromCodePoint((currentChar.codePointAt(0) ?? 0) + 1) + const newChar = currentChar === 'Z' ? 'A' : String.fromCharCode(currentChar.charCodeAt(0) + 1)
135-136: Align guard conditions between ArrowUp and ArrowDown handlers.The ArrowDown handler uses a minimal guard (
!currentCharat line 135), while the ArrowUp handler includes comprehensive bounds checking (line 124:currentChar === undefined || nameInputPosition < 0 || nameInputPosition >= next.length). For consistency and clarity, both branches should use equivalent guards.Apply this diff to align the guards:
setPlayerName(prev => { const next = [...prev] const currentChar = next[nameInputPosition] - if (!currentChar) return prev + if (currentChar === undefined || nameInputPosition < 0 || nameInputPosition >= next.length) return prev const newChar = currentChar === 'A' ? 'Z' : String.fromCodePoint((currentChar.codePointAt(0) ?? 0) - 1) next[nameInputPosition] = newChar return next })src/utils/stable-stringify.ts (2)
84-84: Consider usingsort()for performance.While
toSorted()is more functional, it creates an unnecessary array allocation here. SinceObject.keys()already returns a new array that's only used once, mutating it withsort()is safe and more efficient.Apply this diff if you prefer to optimize:
- const keys = Object.keys(obj as Record<string, unknown>).toSorted() + const keys = Object.keys(obj as Record<string, unknown>).sort()
25-25: Inconsistent undefined check.Line 25 still uses
typeof value === 'undefined', while lines 73 and 89 now use the simplervalue === undefined. For consistency, update line 25 to use the direct comparison as well.Apply this diff for consistency:
- if (valueType === 'undefined' || valueType === 'function' || valueType === 'symbol') { + if (value === undefined || valueType === 'function' || valueType === 'symbol') {Note: You can also simplify by removing the
valueTypecheck entirely since you're already comparing the value directly.src/components/snake/name-input-modal.tsx (1)
38-38: Consider usingreplaceinstead ofreplaceAllwith a global regex.When using a global regex (
/[^A-Z]/g), thereplacemethod already replaces all occurrences. ThereplaceAllmethod is intended for string literals or non-global regex patterns. While this works correctly,replaceis more conventional with global regexes.Apply this diff for consistency:
- .replaceAll(/[^A-Z]/g, '') + .replace(/[^A-Z]/g, '')
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (35)
eslint.config.js(3 hunks)package.json(3 hunks)scripts/build-presence-runtime.ts(2 hunks)scripts/build-theme-runtime.ts(2 hunks)scripts/sync-pet-gallery.ts(3 hunks)src/app/api/local-image/[...path]/route.ts(1 hunks)src/app/api/scores/check/route.ts(1 hunks)src/components/layout/about/aboutme/mode-toggle-link.tsx(1 hunks)src/components/layout/about/pets/pet-card/card-back.tsx(1 hunks)src/components/layout/background/grid-lights.tsx(3 hunks)src/components/layout/header/mobile-nav.tsx(2 hunks)src/components/layout/header/nav-lava.tsx(3 hunks)src/components/layout/home/background-snake-game.tsx(1 hunks)src/components/layout/home/game-overlay.tsx(1 hunks)src/components/layout/home/hero/profile-image.tsx(1 hunks)src/components/layout/pet-gallery/_content.tsx(2 hunks)src/components/providers/achievements-provider.tsx(7 hunks)src/components/providers/confetti-provider.tsx(1 hunks)src/components/providers/review-provider.tsx(1 hunks)src/components/providers/theme-provider.tsx(12 hunks)src/components/snake/name-input-modal.tsx(1 hunks)src/components/ui/theme-toggle.tsx(2 hunks)src/hooks/use-leaderboard.ts(2 hunks)src/lib/game-validation.ts(1 hunks)src/lib/leaderboard.ts(3 hunks)src/lib/score-validation.ts(1 hunks)src/utils/achievements.ts(1 hunks)src/utils/arcade-utils.ts(2 hunks)src/utils/grid.ts(1 hunks)src/utils/presence-script.ts(1 hunks)src/utils/stable-stringify.ts(2 hunks)src/utils/theme-runtime.ts(1 hunks)src/utils/theme-script.ts(5 hunks)src/utils/utils.ts(1 hunks)tsconfig.json(3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx,js,jsx,cjs,mjs}
📄 CodeRabbit inference engine (.cursor/rules/posthog-integration.mdc)
**/*.{ts,tsx,js,jsx,cjs,mjs}: Never hardcode or hallucinate the PostHog API key; always read it from the value populated in the .env file
Create new feature flag names that are clear and descriptive
Gate flag-dependent code on a check that verifies the flag’s values are valid and expected
If a custom property for a person or event is referenced in two or more files or in two or more callsites within the same file, centralize the property name in an enum (TS) or const object (JS)
Files:
src/components/layout/home/background-snake-game.tsxsrc/utils/stable-stringify.tssrc/utils/theme-runtime.tssrc/components/layout/about/pets/pet-card/card-back.tsxsrc/utils/achievements.tssrc/utils/theme-script.tssrc/components/ui/theme-toggle.tsxsrc/components/snake/name-input-modal.tsxsrc/components/providers/theme-provider.tsxsrc/app/api/local-image/[...path]/route.tssrc/components/layout/background/grid-lights.tsxsrc/utils/arcade-utils.tssrc/app/api/scores/check/route.tssrc/components/providers/review-provider.tsxsrc/hooks/use-leaderboard.tsscripts/build-presence-runtime.tssrc/components/layout/about/aboutme/mode-toggle-link.tsxsrc/utils/utils.tssrc/lib/game-validation.tseslint.config.jssrc/components/providers/confetti-provider.tsxscripts/build-theme-runtime.tsscripts/sync-pet-gallery.tssrc/utils/grid.tssrc/components/layout/header/mobile-nav.tsxsrc/components/layout/header/nav-lava.tsxsrc/components/providers/achievements-provider.tsxsrc/components/layout/home/hero/profile-image.tsxsrc/components/layout/home/game-overlay.tsxsrc/components/layout/pet-gallery/_content.tsxsrc/lib/score-validation.tssrc/lib/leaderboard.tssrc/utils/presence-script.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/posthog-integration.mdc)
In TypeScript, store feature flag names in an enum with members written in UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention
**/*.{ts,tsx}: Use Zod for schema validation (client and server)
Model expected errors as return values in Server Actions
Never use unknown or any; always use existing types or define explicit, specific types
Files:
src/components/layout/home/background-snake-game.tsxsrc/utils/stable-stringify.tssrc/utils/theme-runtime.tssrc/components/layout/about/pets/pet-card/card-back.tsxsrc/utils/achievements.tssrc/utils/theme-script.tssrc/components/ui/theme-toggle.tsxsrc/components/snake/name-input-modal.tsxsrc/components/providers/theme-provider.tsxsrc/app/api/local-image/[...path]/route.tssrc/components/layout/background/grid-lights.tsxsrc/utils/arcade-utils.tssrc/app/api/scores/check/route.tssrc/components/providers/review-provider.tsxsrc/hooks/use-leaderboard.tsscripts/build-presence-runtime.tssrc/components/layout/about/aboutme/mode-toggle-link.tsxsrc/utils/utils.tssrc/lib/game-validation.tssrc/components/providers/confetti-provider.tsxscripts/build-theme-runtime.tsscripts/sync-pet-gallery.tssrc/utils/grid.tssrc/components/layout/header/mobile-nav.tsxsrc/components/layout/header/nav-lava.tsxsrc/components/providers/achievements-provider.tsxsrc/components/layout/home/hero/profile-image.tsxsrc/components/layout/home/game-overlay.tsxsrc/components/layout/pet-gallery/_content.tsxsrc/lib/score-validation.tssrc/lib/leaderboard.tssrc/utils/presence-script.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use early returns to simplify control flow and reduce nesting
Use descriptive variable and function names; event handlers prefixed with "handle" (e.g., handleClick, handleKeyDown)
Refactor large files into smaller modules; organize components in folders when refactoring
Standard.js: 2-space indentation; single quotes; no semicolons (unless required); no unused variables; space after keywords; === only; spaced infix operators; commas followed by a space; same-line else; curly braces for multi-line if; camelCase for vars/functions; PascalCase for constructors/React components
Minimize global styles; prefer modular or scoped styles and utility classes
Prioritize error handling and edge cases; use guard clauses and early returns; place happy path last; avoid unnecessary else by using if-return
Naming Convention: enforce consistent naming for files, types, and functions per project rules
Files:
src/components/layout/home/background-snake-game.tsxsrc/utils/stable-stringify.tssrc/utils/theme-runtime.tssrc/components/layout/about/pets/pet-card/card-back.tsxsrc/utils/achievements.tssrc/utils/theme-script.tssrc/components/ui/theme-toggle.tsxsrc/components/snake/name-input-modal.tsxsrc/components/providers/theme-provider.tsxsrc/app/api/local-image/[...path]/route.tssrc/components/layout/background/grid-lights.tsxsrc/utils/arcade-utils.tssrc/app/api/scores/check/route.tssrc/components/providers/review-provider.tsxsrc/hooks/use-leaderboard.tsscripts/build-presence-runtime.tssrc/components/layout/about/aboutme/mode-toggle-link.tsxsrc/utils/utils.tssrc/lib/game-validation.tseslint.config.jssrc/components/providers/confetti-provider.tsxscripts/build-theme-runtime.tsscripts/sync-pet-gallery.tssrc/utils/grid.tssrc/components/layout/header/mobile-nav.tsxsrc/components/layout/header/nav-lava.tsxsrc/components/providers/achievements-provider.tsxsrc/components/layout/home/hero/profile-image.tsxsrc/components/layout/home/game-overlay.tsxsrc/components/layout/pet-gallery/_content.tsxsrc/lib/score-validation.tssrc/lib/leaderboard.tssrc/utils/presence-script.ts
**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.tsx: Use shadcn/ui (and Radix) as the foundation for UI components; install via shadcn CLI, do not create component files manually
Use shadcn/ui components for UI code
Files:
src/components/layout/home/background-snake-game.tsxsrc/components/layout/about/pets/pet-card/card-back.tsxsrc/components/ui/theme-toggle.tsxsrc/components/snake/name-input-modal.tsxsrc/components/providers/theme-provider.tsxsrc/components/layout/background/grid-lights.tsxsrc/components/providers/review-provider.tsxsrc/components/layout/about/aboutme/mode-toggle-link.tsxsrc/components/providers/confetti-provider.tsxsrc/components/layout/header/mobile-nav.tsxsrc/components/layout/header/nav-lava.tsxsrc/components/providers/achievements-provider.tsxsrc/components/layout/home/hero/profile-image.tsxsrc/components/layout/home/game-overlay.tsxsrc/components/layout/pet-gallery/_content.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,jsx}: Implement responsive design with Tailwind CSS; avoid custom style tags and prefer Tailwind utility classes
Add a11y attributes and keyboard handlers (aria-*, onKeyDown) to interactive elements
Use the function keyword for React component definitions (not arrow components for top-level components)
Follow React Hooks rules; use proper hooks (useState, useEffect, useContext, useReducer, useMemo, useCallback)
Extract reusable logic into custom hooks
Use React.memo for component memoization when appropriate
Use useCallback for functions passed as props to avoid unnecessary re-renders
Use useMemo for expensive computations
Avoid inline function definitions in render
Prefer composition over inheritance; use children and render props for flexibility
Use refs sparingly and mainly for DOM access
Prefer controlled components over uncontrolled for forms
Implement error boundaries to catch and handle UI errors
Use cleanup functions in useEffect to prevent memory leaks
Use short-circuit and ternaries for conditional rendering
Minimize 'use client' and client-side hooks; favor React Server Components in Next.js
Wrap client components in with a fallback
Use dynamic loading for non-critical components
Implement route-based code splitting in Next.js
Optimize images in UI: prefer WebP, include intrinsic size, and enable lazy loading when rendering
Use controlled components and client-side validation for forms; consider react-hook-form for complex forms
Provide user-friendly error messages and proper logging in UI paths
Use semantic HTML and proper ARIA attributes; ensure full keyboard navigation
Sanitize user inputs to prevent XSS; avoid dangerouslySetInnerHTML unless content is sanitized
Prefer named exports for components
Files:
src/components/layout/home/background-snake-game.tsxsrc/components/layout/about/pets/pet-card/card-back.tsxsrc/components/ui/theme-toggle.tsxsrc/components/snake/name-input-modal.tsxsrc/components/providers/theme-provider.tsxsrc/components/layout/background/grid-lights.tsxsrc/components/providers/review-provider.tsxsrc/components/layout/about/aboutme/mode-toggle-link.tsxsrc/components/providers/confetti-provider.tsxsrc/components/layout/header/mobile-nav.tsxsrc/components/layout/header/nav-lava.tsxsrc/components/providers/achievements-provider.tsxsrc/components/layout/home/hero/profile-image.tsxsrc/components/layout/home/game-overlay.tsxsrc/components/layout/pet-gallery/_content.tsx
**/*.{js,jsx,cjs,mjs}
📄 CodeRabbit inference engine (.cursor/rules/posthog-integration.mdc)
In JavaScript, store feature flag names as string values in a const object (simulating an enum) with members written in UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention
Files:
eslint.config.js
🧠 Learnings (1)
📚 Learning: 2025-10-03T00:48:27.708Z
Learnt from: kiliantyler
PR: kiliantyler/kil.dev#103
File: src/components/providers/confetti-provider.tsx:214-314
Timestamp: 2025-10-03T00:48:27.708Z
Learning: In src/components/providers/confetti-provider.tsx, the `triggerConfettiChaos` function intentionally creates an infinite confetti loop with no exit condition. This is a deliberate easter egg feature triggered after 20 clicks, and the resource usage is expected behavior. The warning toasts inform users that the only way to stop it is by reloading the page.
Applied to files:
src/components/providers/confetti-provider.tsx
🧬 Code graph analysis (3)
src/components/providers/theme-provider.tsx (2)
src/lib/themes.ts (3)
Theme(57-57)themes(5-53)ThemeName(56-56)src/utils/theme-runtime.ts (1)
getAvailableThemes(79-90)
src/components/providers/achievements-provider.tsx (1)
src/lib/achievements.ts (1)
ACHIEVEMENTS_COOKIE_NAME(4-4)
src/components/layout/home/hero/profile-image.tsx (1)
src/lib/achievements.ts (1)
AchievementId(136-136)
🪛 GitHub Actions: Lint
src/components/layout/header/mobile-nav.tsx
[error] 227-227: TS2345: Argument of type 'Element | null' is not assignable to parameter of type 'HTMLAnchorElement | null'.
🪛 GitHub Check: lint
src/components/ui/theme-toggle.tsx
[failure] 286-286:
Argument of type 'Element | null' is not assignable to parameter of type 'HTMLButtonElement | null'.
src/components/layout/header/mobile-nav.tsx
[failure] 227-227:
Argument of type 'Element | null' is not assignable to parameter of type 'HTMLAnchorElement | null'.
src/components/layout/header/nav-lava.tsx
[failure] 149-149:
Argument of type 'Element | null' is not assignable to parameter of type 'HTMLAnchorElement'.
🔇 Additional comments (52)
src/components/layout/home/background-snake-game.tsx (1)
315-317: Body class toggle looks goodThe toggle with the explicit boolean keeps the class in sync with
isPlaying, and the cleanup still guarantees removal on unmount. No issues spotted here.src/utils/arcade-utils.ts (2)
24-45: LGTM! Robust cleanup implementation.The cleanup function correctly uses
removeEventListenerand includes proper guards, error handling, and a fallback timeout mechanism to handle browser quirks where the 'ended' event may not fire reliably.
47-47: LGTM! Modern event listener API.The migration from the
onendedproperty toaddEventListenerfollows best practices and aligns with modern DOM API usage.src/components/providers/review-provider.tsx (1)
13-13: LGTM! Clean simplification.Removing the explicit
undefinedargument is correct—TypeScript infersundefinedas the initial value for optional types when no argument is provided.src/components/layout/background/grid-lights.tsx (3)
49-49: LGTM! Modern array access pattern.The use of
at(-1)is more concise thanpoints[points.length - 1]and aligns with the ES2023 target. The non-null assertions are safe since the points array is guaranteed to have elements at these call sites.Also applies to: 54-54
80-80: LGTM! Consistent modernization.The same
at(-1)pattern is applied consistently in the vertical path generation, matching the horizontal path changes. The non-null assertions are safe.Also applies to: 85-85
105-108: LGTM! Consolidated push operation.Combining two successive
push()calls into a single call with multiple arguments is functionally equivalent and slightly more efficient. The keyframe order and animation behavior remain unchanged.src/utils/utils.ts (1)
9-21: LGTM! Improved NaN validation.The switch from
isNaNtoNumber.isNaNis correct and follows modern JavaScript best practices. Sinced.getTime()always returns a number type,Number.isNaNprovides more precise type checking without unnecessary coercion.src/app/api/scores/check/route.ts (1)
16-18: LGTM! Consistent numeric handling modernization.The changes from
parseInttoNumber.parseIntand fromisNaNtoNumber.isNaNalign with modern JavaScript best practices and maintain consistency with the broader codebase pattern (e.g.,src/utils/utils.ts). The validation logic remains correct and the changes are safe.src/utils/stable-stringify.ts (2)
73-73: LGTM! Simplified undefined check.The change from
typeof item === 'undefined'toitem === undefinedis clearer and more idiomatic. Sinceitemis from array iteration, it's always declared, making the direct comparison safe.
89-89: LGTM! Simplified undefined check.The change from
typeof val === 'undefined'toval === undefinedis clearer and more idiomatic, consistent with the change on line 73.tsconfig.json (1)
6-6: LGTM! TypeScript target appropriately updated to ES2023.The bump from ES2022 to ES2023 correctly enables modern JavaScript features used throughout the PR, including
Array.prototype.at,replaceAll, and top-level await in scripts.Also applies to: 20-20
src/lib/game-validation.ts (1)
3-3: LGTM! Node.js built-in import modernized.The
node:cryptoprefix is the recommended pattern for importing Node.js built-ins, improving clarity and preventing potential conflicts with userland modules.src/components/layout/about/aboutme/mode-toggle-link.tsx (1)
69-69: LGTM! Modern DOM API usage.The
append()method is the modern API for inserting nodes, offering more flexibility thanappendChild()(e.g., accepting multiple arguments and DOMStrings).src/app/api/local-image/[...path]/route.ts (1)
2-3: LGTM! Node.js built-in imports modernized.The
node:prefix for built-ins improves clarity and prevents conflicts with userland modules, aligning with current Node.js best practices.src/utils/theme-runtime.ts (1)
11-11: LGTM! Modernized data attribute check.Using
Object.hasOwn(root.dataset, 'hasThemeTapdance')is the modern, idiomatic approach for checking dataset properties. ThedatasetAPI automatically converts kebab-case attribute names to camelCase property names.src/utils/grid.ts (1)
41-42: LGTM! More robust window existence check.The strict
=== undefinedcomparison is more precise than a truthy check, correctly handling edge cases whereglobalThis.windowmight benullor other falsy but defined values.src/components/layout/home/game-overlay.tsx (1)
29-29: LGTM! Simplified keyboard handler logic.The combined conditional
e.key === ' ' && (gameOver || !isPlaying)is more concise and readable than a multi-step check, while preserving the exact same behavior.scripts/build-theme-runtime.ts (2)
5-14: LGTM! Clean path module modernization.The changes correctly modernize the path handling:
- Default import of
pathmodule is idiomatic for Node.js- Explicit
path.dirname(__filename)andpath.resolve(...)calls improve clarity- Consistent with the broader codebase modernization pattern
43-47: LGTM! Top-level await is appropriate.Using top-level
awaitwith the main function is a modern ESM pattern that simplifies error handling at the script entry point.src/lib/score-validation.ts (1)
37-43: LGTM! Explicit global replacement intent.The change from
replace(/[^A-Z]/g, '')toreplaceAll(/[^A-Z]/g, '')is functionally equivalent but more explicit about performing a global replacement. This aligns with the codebase modernization pattern seen across the PR.src/components/ui/theme-toggle.tsx (2)
118-118: LGTM! Modern DOM API usage.The change from
appendChild(style)toappend(style)uses the modern DOM API, which is more concise and aligns with the codebase modernization pattern seen in other files (e.g., mobile-nav.tsx, mode-toggle-link.tsx).
289-289: LGTM! More explicit -1 check.The change from
currentIndex < 0tocurrentIndex === -1is more explicit and aligns with the standard convention for checking "not found" results fromindexOf.src/components/layout/pet-gallery/_content.tsx (3)
5-6: LGTM! Node built-in import modernization.The change to
node:fsandnode:pathimports follows Node.js best practices and aligns with the modernization pattern throughout the codebase (also seen in build-theme-runtime.ts, build-presence-runtime.ts).
42-42: LGTM! Non-mutating array sort.Using
toSortedinstead ofsortcreates a new sorted array without mutating the original, which is a better functional programming practice and aligns with modern JavaScript idioms.
48-50: LGTM! Explicit global replacement with replaceAll.The changes from
replacetoreplaceAllwith regex patterns make the global replacement intent explicit and align with the codebase modernization pattern.src/components/layout/about/pets/pet-card/card-back.tsx (1)
41-41: LGTM! Explicit null handling.The explicit
ageYears === nullcheck improves code clarity and makes the null-handling behavior more obvious. This aligns with the stricter type-checking patterns seen throughout the PR.eslint.config.js (3)
3-3: LGTM! Unicorn plugin integration.Adding
eslint-plugin-unicornenhances linting capabilities with modern JavaScript best practices, as evidenced by the codebase modernizations throughout this PR.
28-28: LGTM! Unopinionated preset choice.Using the unopinionated preset provides a good balance of useful rules without being overly prescriptive, which is appropriate for an established codebase.
43-44: LGTM! Rule disabling with tracked TODO.Disabling
unicorn/no-nested-ternaryis acknowledged with a TODO comment noting the Prettier conflict. This is good practice for tracking known technical debt.The
unicorn/numeric-separators-styledisable is also reasonable as a style preference.package.json (3)
44-44: LGTM! Correct js-cookie version.The
js-cookieversion 3.0.5 is the latest published runtime release, as confirmed by the official npm package. This aligns with the cookie handling migration seen in theme-provider.tsx and achievements-provider.tsx.Based on learnings.
67-68: LGTM! Type dependencies correctly organized.Moving
@types/canvas-confettito devDependencies is correct since types are only needed at build time. The@types/js-cookieversion 3.0.6 is from DefinitelyTyped and provides the latest type definitions for the js-cookie 3.x API.Based on learnings.
72-72: LGTM! ESLint plugin addition.The
eslint-plugin-unicorndevDependency aligns with the ESLint configuration changes in eslint.config.js and enables the modern JavaScript linting rules applied throughout this PR.scripts/sync-pet-gallery.ts (2)
95-95: LGTM!The use of
replaceAllwith two passes (dashes/underscores → space, then collapse multiple spaces) is clear and correct.
193-198: LGTM!The top-level await pattern with error handling and explicit exit code is consistent with other build scripts in the repository.
scripts/build-presence-runtime.ts (2)
5-14: LGTM!The migration to
node:pathdefault import and explicitpath.dirname/path.resolveusage aligns with the broader project refactor to use Node built-in modules consistently.
43-47: LGTM!The top-level await pattern with error handling is correct and consistent with other build scripts.
src/lib/leaderboard.ts (1)
25-25: LGTM!The updates to use
=== -1for not-found checks and.at(-1)for last-element access improve code clarity and align with modern JavaScript conventions.Also applies to: 49-49, 133-133
src/utils/theme-script.ts (1)
34-34: LGTM!The updates to use modern DOM APIs (
append,remove),Object.hasOwnfor dataset checks, and optional chaining formatchMediaimprove code safety and align with modern JavaScript conventions.Also applies to: 92-93, 103-103, 122-122, 151-151
src/components/providers/theme-provider.tsx (6)
10-10: LGTM!The migration to
js-cookiefor cookie handling is correct. The usage ofCookies.setwith options (path,maxAge,samesite,secure) aligns with the v3.x API, which requires options to be passed per-call rather than via global defaults.Based on learnings
Also applies to: 111-122, 140-145
56-56: LGTM!Refactoring
VALID_THEMESto aSetand usinghasfor lookups is more efficient thanArray.includesand aligns with best practices for fast membership checks.Also applies to: 65-65, 75-75, 87-87, 98-98
37-54: LGTM!The refactor of
coerceToValidThemewith a default parameter and simplified validation logic is correct. The use ofObject.hasOwnfor dataset checks is safer than attribute-based checks.
213-213: LGTM!The bare returns in server-side branches preserve the same behavior while simplifying the code.
Also applies to: 223-223, 227-227, 234-234
346-346: LGTM!The use of
Object.hasOwnfor dataset checks is safer and more direct than attribute-based checks.
374-379: LGTM!The simplified ternary for
computedInitialpreserves the same behavior while improving readability.src/utils/achievements.ts (1)
65-67: LGTM!The use of
replaceAllto escape<,\u2028, and\u2029ensures the JSON is safe when embedded in HTML and prevents XSS vulnerabilities.src/components/providers/confetti-provider.tsx (1)
26-31: LGTM!The updated catch block with an empty comment makes the intent clearer while preserving the same behavior of swallowing promise rejections.
src/components/layout/header/mobile-nav.tsx (2)
85-85: LGTM!The use of
document.head.appendaligns with modern DOM APIs and is consistent with other updates in the repository.
230-230: LGTM!The
currentIndex === -1check correctly handles the not-found case and aligns with the updated patterns in the codebase.src/components/providers/achievements-provider.tsx (1)
179-244: LGTM! Modern dataset API usage.The migration from
setAttribute/removeAttributeto dataset property assignments and thedeleteoperator is a clean, modern approach that aligns with current DOM API best practices. This improves SSR hydration consistency and simplifies the code.src/components/layout/header/nav-lava.tsx (2)
41-42: LGTM! Modern dataset API usage.The refactor from
getAttributetodataset.*is idiomatic and aligns with modern DOM best practices. The string equality checks (=== 'true') correctly handle the fact that dataset values are always strings.
91-99: LGTM! Improved animation initialization logic.The conditional logic ensures the indicator snaps into place without animation on first render, then enables smooth transitions for subsequent updates. The use of
requestAnimationFrameto defer the animation flag is appropriate and prevents visual flicker.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/layout/header/mobile-nav.tsx(2 hunks)src/components/layout/header/nav-lava.tsx(3 hunks)src/components/ui/theme-toggle.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/layout/header/nav-lava.tsx
- src/components/ui/theme-toggle.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,cjs,mjs}
📄 CodeRabbit inference engine (.cursor/rules/posthog-integration.mdc)
**/*.{ts,tsx,js,jsx,cjs,mjs}: Never hardcode or hallucinate the PostHog API key; always read it from the value populated in the .env file
Create new feature flag names that are clear and descriptive
Gate flag-dependent code on a check that verifies the flag’s values are valid and expected
If a custom property for a person or event is referenced in two or more files or in two or more callsites within the same file, centralize the property name in an enum (TS) or const object (JS)
Files:
src/components/layout/header/mobile-nav.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/posthog-integration.mdc)
In TypeScript, store feature flag names in an enum with members written in UPPERCASE_WITH_UNDERSCORE and use a consistent naming convention
**/*.{ts,tsx}: Use Zod for schema validation (client and server)
Model expected errors as return values in Server Actions
Never use unknown or any; always use existing types or define explicit, specific types
Files:
src/components/layout/header/mobile-nav.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use early returns to simplify control flow and reduce nesting
Use descriptive variable and function names; event handlers prefixed with "handle" (e.g., handleClick, handleKeyDown)
Refactor large files into smaller modules; organize components in folders when refactoring
Standard.js: 2-space indentation; single quotes; no semicolons (unless required); no unused variables; space after keywords; === only; spaced infix operators; commas followed by a space; same-line else; curly braces for multi-line if; camelCase for vars/functions; PascalCase for constructors/React components
Minimize global styles; prefer modular or scoped styles and utility classes
Prioritize error handling and edge cases; use guard clauses and early returns; place happy path last; avoid unnecessary else by using if-return
Naming Convention: enforce consistent naming for files, types, and functions per project rules
Files:
src/components/layout/header/mobile-nav.tsx
**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.tsx: Use shadcn/ui (and Radix) as the foundation for UI components; install via shadcn CLI, do not create component files manually
Use shadcn/ui components for UI code
Files:
src/components/layout/header/mobile-nav.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,jsx}: Implement responsive design with Tailwind CSS; avoid custom style tags and prefer Tailwind utility classes
Add a11y attributes and keyboard handlers (aria-*, onKeyDown) to interactive elements
Use the function keyword for React component definitions (not arrow components for top-level components)
Follow React Hooks rules; use proper hooks (useState, useEffect, useContext, useReducer, useMemo, useCallback)
Extract reusable logic into custom hooks
Use React.memo for component memoization when appropriate
Use useCallback for functions passed as props to avoid unnecessary re-renders
Use useMemo for expensive computations
Avoid inline function definitions in render
Prefer composition over inheritance; use children and render props for flexibility
Use refs sparingly and mainly for DOM access
Prefer controlled components over uncontrolled for forms
Implement error boundaries to catch and handle UI errors
Use cleanup functions in useEffect to prevent memory leaks
Use short-circuit and ternaries for conditional rendering
Minimize 'use client' and client-side hooks; favor React Server Components in Next.js
Wrap client components in with a fallback
Use dynamic loading for non-critical components
Implement route-based code splitting in Next.js
Optimize images in UI: prefer WebP, include intrinsic size, and enable lazy loading when rendering
Use controlled components and client-side validation for forms; consider react-hook-form for complex forms
Provide user-friendly error messages and proper logging in UI paths
Use semantic HTML and proper ARIA attributes; ensure full keyboard navigation
Sanitize user inputs to prevent XSS; avoid dangerouslySetInnerHTML unless content is sanitized
Prefer named exports for components
Files:
src/components/layout/header/mobile-nav.tsx
🔇 Additional comments (2)
src/components/layout/header/mobile-nav.tsx (2)
85-85: LGTM!The modernization from
appendChildtoappendaligns with contemporary DOM APIs and matches the PR's goal of code modernization.
230-230: Good refinement.Using
=== -1is more explicit and idiomatic forindexOfresults than< 0, improving readability.
|



Improves code quality and consistency by refining ESLint configuration and rules:
eslint-plugin-unicornfor enhanced linting rules.js-cookieThis also includes updates to dependencies and build configurations.
Summary by CodeRabbit
Bug Fixes
Refactor
Chores