Skip to content

Enhances achievements with images and confetti#45

Merged
kiliantyler merged 8 commits intomainfrom
feat/achivement-images
Sep 18, 2025
Merged

Enhances achievements with images and confetti#45
kiliantyler merged 8 commits intomainfrom
feat/achivement-images

Conversation

@kiliantyler
Copy link
Copy Markdown
Collaborator

@kiliantyler kiliantyler commented Sep 18, 2025

Adds images to achievements and introduces confetti effects upon unlocking certain achievements, enhancing the user experience.

  • Implements a confetti provider and integrates it with achievement unlocks.
  • Adds achievement images to better represent each achievement.
  • Adds a confetti cannon to footer.
  • Refactors images with index.ts files to keep code organized and clean.

Summary by CodeRabbit

  • New Features
    • Confetti system added with multiple trigger styles; clickable name in the footer launches confetti; select achievements now trigger confetti on unlock.
  • Refactor
    • Image assets centralized (pets, headshots, logos, projects, achievements) for consistent usage; no UI changes.
  • Chores
    • Build script updated to run a prebuild step before Storybook; added confetti library and TypeScript typings as dependencies.

@vercel
Copy link
Copy Markdown

vercel bot commented Sep 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
kil-dev Ready Ready Preview Comment Sep 18, 2025 3:51am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 18, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a client-side ConfettiProvider and useConfetti hook, wires confetti triggers into AchievementsProvider and Footer, adds a required confetti flag to achievement definitions, centralizes many image assets via index re-exports, updates consumers to use namespace imports, and adds canvas-confetti (+ types) to package.json.

Changes

Cohort / File(s) Summary
Dependencies
package.json
Adds canvas-confetti@1.9.3 and @types/canvas-confetti@1.9.0; updates build-storybook script to run bun run prebuild && storybook build.
Confetti system & integration
src/components/providers/confetti-provider.tsx, src/components/providers/providers.tsx, src/components/providers/achievements-provider.tsx, src/components/layout/footer.tsx, src/types/achievements.d.ts, src/lib/achievements.ts
Adds a client ConfettiProvider and useConfetti() (exposes triggerConfetti, triggerConfettiFromCorners, triggerConfettiFromTop, triggerConfettiFromCenter); wraps AchievementsProvider with ConfettiProvider; AchievementsProvider triggers corner confetti when an achievement’s confetti flag is true (with simple throttling); Footer becomes a client component and triggers corner confetti on author-name click; adds confetti: boolean to AchievementDefinition and updates ACHIEVEMENTS entries to include the flag and use centralized image exports.
Image index modules (new)
src/images/achievements/index.ts, src/images/headshot/index.ts, src/images/logos/index.ts, src/images/pets/index.ts, src/images/projects/index.ts
Adds index files that re-export named image assets for achievements, headshots, logos, pets, and projects.
Image import consolidation (namespace usage)
src/app/about/head.tsx, src/components/layout/home/hero/profile-image.tsx, src/lib/experience.ts, src/lib/pets.ts, src/lib/projects.ts, src/lib/themes.ts
Replaces multiple per-file asset imports with single namespace imports from the new index modules and updates references to use the namespace (e.g., Pets.*, Headshots.*, Logos.*, Projects.*, Images.*).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Footer as Footer (client)
  participant Confetti as ConfettiProvider
  participant Canvas as canvas-confetti

  User->>Footer: Click "Kilian Tyler"
  Footer->>Confetti: triggerConfettiFromCorners()
  Note over Confetti: Check/throttle pending set (~1s)
  Confetti->>Canvas: Fire left/right bursts (angles/origins)
  Canvas-->>Confetti: Rendered
  Confetti-->>Footer: Completed
Loading
sequenceDiagram
  autonumber
  participant App as UI
  participant AchProv as AchievementsProvider
  participant Toast as ToastSystem
  participant Confetti as ConfettiProvider
  participant Canvas as canvas-confetti

  App->>AchProv: unlock(achievementId)
  AchProv->>Toast: show unlocked toast
  alt achievement.confetti && not pending
    AchProv->>Confetti: triggerConfettiFromCorners()
    Note over Confetti: Throttle pending id (~1s)
    Confetti->>Canvas: Fire corner bursts
    Canvas-->>Confetti: Rendered
  else no confetti
    Note over AchProv: No confetti triggered
  end
  AchProv-->>App: unlock complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly and accurately captures the primary change set — adding images to achievements and introducing confetti effects — and directly aligns with the PR objectives and file diffs (image index additions, ACHIEVEMENTS confetti flags, and the confetti provider integration). It is concise, specific, and readable for teammates scanning history.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38edb1e and 79dbd9d.

📒 Files selected for processing (3)
  • package.json (2 hunks)
  • src/components/providers/confetti-provider.tsx (1 hunks)
  • src/components/providers/theme-provider.tsx (0 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

@kiliantyler kiliantyler merged commit e9bcf84 into main Sep 18, 2025
5 checks passed
@kiliantyler kiliantyler deleted the feat/achivement-images branch September 18, 2025 03:51
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
src/images/pets/index.ts (1)

1-6: Same: avoid index.ts barrels; move to a concrete module

Rename to a non-index module (e.g., src/images/pets.ts) or import assets directly; update all imports accordingly.

src/images/projects/index.ts (1)

1-5: Same: avoid index.ts barrels; move to a concrete module

Rename to a non-index module (e.g., src/images/projects.ts) or import assets directly; update all imports accordingly.

🧹 Nitpick comments (12)
package.json (2)

37-37: Move @types to devDependencies

@types/canvas-confetti should be a devDependency to avoid bloating prod installs.

-    "@types/canvas-confetti": "1.9.0",
+    

And add under devDependencies:

   "devDependencies": {
+    "@types/canvas-confetti": "1.9.0",

39-39: Optional: lazy‑load canvas-confetti to trim initial bundle

Importing at module scope ships confetti on every page load. Consider dynamic import inside trigger methods.

-import confetti from 'canvas-confetti'
+let _confetti: typeof import('canvas-confetti')['default'] | null = null
+const getConfetti = async () => (_confetti ??= (await import('canvas-confetti')).default)

Then replace calls like:

-void confetti({...})
+;(await getConfetti())({ ... })
src/components/providers/confetti-provider.tsx (6)

1-1: Fix Prettier warning

CI flagged formatting. Run prettier --write on this file.


18-24: Respect reduced‑motion users

Add disableForReducedMotion to avoid triggering animations for users who prefer reduced motion.

   const triggerConfetti = useCallback(() => {
-    void confetti({
+    void confetti({
       particleCount: 100,
       spread: 70,
       origin: { y: 0.6 },
+      disableForReducedMotion: true,
     })
   }, [])

26-52: Remove unsupported props; add a11y flag

x and y at top level are not confetti options (use origin). Also add disableForReducedMotion.

   const leftCorner = {
-      x: 0,
-      y: 1,
       angle: 45,
       startVelocity: 55,
       spread: 90,
       particleCount: 50,
       origin: { x: 0, y: 1 },
+      disableForReducedMotion: true,
   }
 
   const rightCorner = {
-      x: 1,
-      y: 1,
       angle: 135,
       startVelocity: 55,
       spread: 90,
       particleCount: 50,
       origin: { x: 1, y: 1 },
+      disableForReducedMotion: true,
   }

62-77: Add reduced‑motion guard (top)

Same rationale as above.

   void confetti({
     particleCount: 150,
     spread: 180,
     origin: { y: 0 },
     angle: 270,
     startVelocity: 45,
+    disableForReducedMotion: true,
   })

79-93: Add reduced‑motion guard (center)

Maintain consistency across triggers.

   void confetti({
     particleCount: 200,
     spread: 360,
     origin: { x: 0.5, y: 0.5 },
     startVelocity: 30,
+    disableForReducedMotion: true,
   })

95-103: Optional: dedupe helper to DRY pending logic

Extract a withDedupe(id, fn) to reduce repetition and centralize cleanup.

-const value = useMemo<ConfettiContextValue>(
+const withDedupe = useCallback((id: string, fn: () => void) => {
+  if (pendingConfettiRef.current.has(id)) return
+  pendingConfettiRef.current.add(id)
+  fn()
+  setTimeout(() => pendingConfettiRef.current.delete(id), 1000)
+}, [])
+
+const value = useMemo<ConfettiContextValue>(
   () => ({
-      triggerConfetti,
-      triggerConfettiFromCorners,
-      triggerConfettiFromTop,
-      triggerConfettiFromCenter,
+    triggerConfetti,
+    triggerConfettiFromCorners: () => withDedupe('corners', () => { void confetti({ /* ... */ }) }),
+    triggerConfettiFromTop: () => withDedupe('top', () => { void confetti({ /* ... */ }) }),
+    triggerConfettiFromCenter: () => withDedupe('center', () => { void confetti({ /* ... */ }) }),
   }),
-  [triggerConfetti, triggerConfettiFromCorners, triggerConfettiFromTop, triggerConfettiFromCenter],
+  [triggerConfetti, withDedupe],
 )

Note: Inline the specific options as shown in existing functions.

src/components/layout/footer.tsx (1)

11-19: Convert inline handler to named handler and set type="button"

Aligns with guidelines (no inline handlers; handler prefix handle*). Prevents accidental form submit.

 export function Footer() {
-  const { triggerConfettiFromCorners } = useConfetti()
+  const { triggerConfettiFromCorners } = useConfetti()
+  const handleNameClick = React.useCallback(() => {
+    triggerConfettiFromCorners()
+  }, [triggerConfettiFromCorners])
 
   return (
 ...
-            <button
-              onClick={() => {
-                triggerConfettiFromCorners()
-              }}>
+            <button type="button" onClick={handleNameClick} aria-label="Celebrate with confetti">
               Kilian Tyler
             </button>
src/app/about/head.tsx (1)

6-11: Preload budget: consider downsizing or using next/image priority

Preloading 6 images can be heavy. If only some appear above the fold, prefer next/image with priority or reduce to critical assets only.

src/components/layout/home/hero/profile-image.tsx (1)

159-168: Drop priority/eager on overlay to protect LCP

The overlay image sits above the themed base images; marking it priority/eager can regress LCP. Let it lazy-load unless absolutely needed on first paint.

Apply this diff:

           <Image
             alt={imageAlt}
             src={imageSrc}
             className={`${isEnvDrivenVariant && !isImageLoaded ? 'opacity-0' : 'opacity-100'} rounded-lg transition-transform duration-500 ease-(--ease-fluid) translate-y-0 scale-100 transform-gpu group-hover:-translate-y-1 group-hover:scale-105`}
-            loading="eager"
-            priority
+            loading="lazy"
             fill
             sizes="(min-width: 1024px) 500px, 100vw"
             onLoad={() => setIsImageLoaded(true)}
           />
src/components/providers/providers.tsx (1)

22-24: Provider order is correct; add reduced‑motion + lazy confetti load

ConfettiProvider placement looks good. To reduce bundle cost and respect a11y, gate animations on prefers‑reduced‑motion and dynamically import canvas‑confetti inside the provider’s trigger functions.

Apply in src/components/providers/confetti-provider.tsx (illustrative):

-  const triggerConfetti = useCallback(() => {
-    void confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } })
-  }, [])
+  const triggerConfetti = useCallback(() => {
+    if (typeof window === 'undefined') return
+    if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) return
+    void import('canvas-confetti').then(m =>
+      m.default({ particleCount: 100, spread: 70, origin: { y: 0.6 } })
+    )
+  }, [])

Repeat the same pattern for fromCorners/fromTop/fromCenter.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7995794 and 38edb1e.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • package.json (1 hunks)
  • src/app/about/head.tsx (1 hunks)
  • src/components/layout/footer.tsx (1 hunks)
  • src/components/layout/home/hero/profile-image.tsx (2 hunks)
  • src/components/providers/achievements-provider.tsx (2 hunks)
  • src/components/providers/confetti-provider.tsx (1 hunks)
  • src/components/providers/providers.tsx (2 hunks)
  • src/images/achievements/index.ts (1 hunks)
  • src/images/headshot/index.ts (1 hunks)
  • src/images/logos/index.ts (1 hunks)
  • src/images/pets/index.ts (1 hunks)
  • src/images/projects/index.ts (1 hunks)
  • src/lib/achievements.ts (2 hunks)
  • src/lib/experience.ts (4 hunks)
  • src/lib/pets.ts (7 hunks)
  • src/lib/projects.ts (6 hunks)
  • src/lib/themes.ts (1 hunks)
  • src/types/achievements.d.ts (1 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/providers/providers.tsx
  • src/images/pets/index.ts
  • src/app/about/head.tsx
  • src/images/headshot/index.ts
  • src/images/projects/index.ts
  • src/components/layout/home/hero/profile-image.tsx
  • src/lib/pets.ts
  • src/images/logos/index.ts
  • src/components/layout/footer.tsx
  • src/types/achievements.d.ts
  • src/components/providers/confetti-provider.tsx
  • src/lib/projects.ts
  • src/lib/experience.ts
  • src/images/achievements/index.ts
  • src/lib/themes.ts
  • src/components/providers/achievements-provider.tsx
  • src/lib/achievements.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/providers/providers.tsx
  • src/images/pets/index.ts
  • src/app/about/head.tsx
  • src/images/headshot/index.ts
  • src/images/projects/index.ts
  • src/components/layout/home/hero/profile-image.tsx
  • src/lib/pets.ts
  • src/images/logos/index.ts
  • src/components/layout/footer.tsx
  • src/types/achievements.d.ts
  • src/components/providers/confetti-provider.tsx
  • src/lib/projects.ts
  • src/lib/experience.ts
  • src/images/achievements/index.ts
  • src/lib/themes.ts
  • src/components/providers/achievements-provider.tsx
  • src/lib/achievements.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/providers/providers.tsx
  • src/images/pets/index.ts
  • src/app/about/head.tsx
  • src/images/headshot/index.ts
  • src/images/projects/index.ts
  • src/components/layout/home/hero/profile-image.tsx
  • src/lib/pets.ts
  • src/images/logos/index.ts
  • src/components/layout/footer.tsx
  • src/types/achievements.d.ts
  • src/components/providers/confetti-provider.tsx
  • src/lib/projects.ts
  • src/lib/experience.ts
  • src/images/achievements/index.ts
  • src/lib/themes.ts
  • src/components/providers/achievements-provider.tsx
  • src/lib/achievements.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/providers/providers.tsx
  • src/app/about/head.tsx
  • src/components/layout/home/hero/profile-image.tsx
  • src/components/layout/footer.tsx
  • src/components/providers/confetti-provider.tsx
  • src/components/providers/achievements-provider.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/providers/providers.tsx
  • src/app/about/head.tsx
  • src/components/layout/home/hero/profile-image.tsx
  • src/components/layout/footer.tsx
  • src/components/providers/confetti-provider.tsx
  • src/components/providers/achievements-provider.tsx
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not create index.ts files; import from concrete module paths

Files:

  • src/images/pets/index.ts
  • src/images/headshot/index.ts
  • src/images/projects/index.ts
  • src/images/logos/index.ts
  • src/images/achievements/index.ts
🧬 Code graph analysis (3)
src/components/providers/providers.tsx (2)
src/components/providers/confetti-provider.tsx (1)
  • ConfettiProvider (15-106)
src/components/providers/achievements-provider.tsx (1)
  • AchievementsProvider (56-293)
src/components/layout/footer.tsx (1)
src/components/providers/confetti-provider.tsx (1)
  • useConfetti (108-112)
src/components/providers/achievements-provider.tsx (2)
src/components/providers/confetti-provider.tsx (1)
  • useConfetti (108-112)
src/lib/achievements.ts (1)
  • ACHIEVEMENTS (6-112)
🪛 GitHub Actions: Lint
src/components/providers/confetti-provider.tsx

[warning] 1-1: Prettier formatting issues found in 'src/components/providers/confetti-provider.tsx'. Run 'prettier --write' to fix.

🔇 Additional comments (12)
src/types/achievements.d.ts (1)

12-12: New required field: ensure all definitions are updated

confetti is now required. Confirm all AchievementDefinition objects (e.g., in src/lib/achievements.ts) set this flag to avoid TS breaks at build.

src/components/providers/confetti-provider.tsx (1)

108-111: Providers order: verify ConfettiProvider wraps all consumers

useConfetti throws if missing provider. Confirm src/components/providers/providers.tsx includes ConfettiProvider above AchievementsProvider and Footer mounts under it.

src/lib/themes.ts (2)

1-1: LGTM — asset import consolidation

Namespace import cleans up consumers and keeps assets centralized.


9-10: Verify assets exported from index

Ensure Headshots.Headshot, .Cyberpunk, .Halloween, .Thanksgiving exist in src/images/headshot/index.ts and are StaticImageData.

Also applies to: 16-17, 23-24, 30-31, 38-39

src/lib/projects.ts (2)

1-1: LGTM — projects images via namespace

Consistent with the new assets pattern.


14-15: Type check imageSrc types

Confirm Projects.* exports are StaticImageData to satisfy Project.imageSrc type.

Also applies to: 25-26, 37-38, 53-54, 63-64

src/lib/pets.ts (1)

1-1: LGTM — pets images via namespace

Good consolidation; alt text remains descriptive.

src/components/layout/home/hero/profile-image.tsx (1)

29-31: LGTM: typed variant-to-image mapping

The StaticImageData mapping via the namespace import is correct and keeps variant handling clean.

src/lib/experience.ts (1)

28-28: LGTM: logo assignments now reference consolidated exports

Namespace usage reads clearly and matches the typed structure.

Also applies to: 49-49, 70-70

src/lib/achievements.ts (1)

12-18: LGTM: image consolidation and confetti flags

Switch to Images.* and explicit confetti booleans align with the provider’s behavior.

Also applies to: 24-29, 35-41, 47-52, 58-64, 70-75, 81-87, 93-98, 104-111

src/components/providers/achievements-provider.tsx (1)

114-141: Confetti gating and de‑dupe look good — provider nesting verified.
AchievementsProvider is only rendered inside in src/components/providers/providers.tsx (line 23); Providers is mounted in src/app/layout.tsx (lines 64–75).

src/images/headshot/index.ts (1)

1-7: Remove barrel (src/images/headshot/index.ts) — import images from concrete paths

This index.ts creates a barrel and violates the repo guideline "Do not create index.ts files; import from concrete module paths".

  • Option A (preferred): remove this file and update callsites to import assets directly, e.g. import Confused from '@/images/headshot/cartoon-confused.webp'.
  • Option B: if an aggregator is required, rename/create a concrete module like src/images/headshot/headshots.ts and export the assets from there.

Verified: index barrels exist at src/images/{achievements, headshot, logos, pets, projects}/index.ts and tsconfig.json maps "@/*""./src/*". Automated search did not locate callsites; confirm usage and update imports accordingly.

import Confused from '@/images/headshot/cartoon-confused.webp'
import Grumpy from '@/images/headshot/cartoon-grumpy.webp'
import Ladybird from '@/images/headshot/cartoon-ladybird.webp'
import * as Headshots from '@/images/headshot'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid barrel import (index.ts) per repo rule

Guideline says “Do not create index.ts files; import from concrete module paths.” Replace the barrel at @/images/headshot with a concrete module (e.g., a named module like @/images/headshot.ts or direct asset imports) and remove the underlying index.ts.

🤖 Prompt for AI Agents
In src/components/layout/home/hero/profile-image.tsx around line 6, the file
currently does a barrel import from '@/images/headshot' which violates the repo
rule against index.ts barrels; replace that line with concrete imports from the
actual module(s) (for example import specific named exports from
'@/images/headshot.ts' or import individual asset files like
'@/images/headshot.jpg' or '@/images/headshot.png' as used in this component),
adjust any references to Headshots.* to the new local names, and remove the
underlying index.ts barrel file from the images/headshot directory so future
imports must use the concrete module paths.

Comment on lines +1 to +11
export { default as AboutAmblerAchievement } from './about-ambler.webp'
export { default as ConfusedClickAchievement } from './confused-click.webp'
export { default as ExperienceExplorerAchievement } from './experience-explorer.webp'
export { default as GrumpyGlimpseAchievement } from './grumpy-glimpse.webp'
export { default as LadybirdLandingAchievement } from './ladybird-landing.webp'
export { default as PetParadeAchievement } from './pet-parade.webp'
export { default as PlaceholderAchievement } from './placeholder.webp'
export { default as ProjectsPeruserAchievement } from './projects-peruser.webp'
export { default as RecursiveRewardAchievement } from './recursive-reward.webp'
export { default as ThemeTapdanceAchievement } from './theme-tapdance.webp'
export { default as UnknownAchievement } from './unknown.webp'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

❓ Verification inconclusive

No index.ts per guidelines: switch to concrete imports or a named aggregator module

Same guideline applies here. Either import assets directly where used, or move these re-exports into a concrete file name (e.g., achievementImages.ts) and import via @/images/achievements/achievementImages.

If keeping an aggregator, create src/images/achievements/achievementImages.ts:

export { default as AboutAmblerAchievement } from './about-ambler.webp'
export { default as ConfusedClickAchievement } from './confused-click.webp'
export { default as ExperienceExplorerAchievement } from './experience-explorer.webp'
export { default as GrumpyGlimpseAchievement } from './grumpy-glimpse.webp'
export { default as LadybirdLandingAchievement } from './ladybird-landing.webp'
export { default as PetParadeAchievement } from './pet-parade.webp'
export { default as PlaceholderAchievement } from './placeholder.webp'
export { default as ProjectsPeruserAchievement } from './projects-peruser.webp'
export { default as RecursiveRewardAchievement } from './recursive-reward.webp'
export { default as ThemeTapdanceAchievement } from './theme-tapdance.webp'
export { default as UnknownAchievement } from './unknown.webp'

Minor: Namespace barrels may reduce treeshaking; direct per-asset imports are safest for bundle size.


Remove the barrel index.ts — import assets directly or use a named aggregator

Per repo guideline, avoid index.ts barrels. Either import each .webp where used, or replace this barrel with a concrete module (e.g., src/images/achievements/achievementImages.ts).

Suggested aggregator (if keeping one):

export { default as AboutAmblerAchievement } from './about-ambler.webp'
export { default as ConfusedClickAchievement } from './confused-click.webp'
export { default as ExperienceExplorerAchievement } from './experience-explorer.webp'
export { default as GrumpyGlimpseAchievement } from './grumpy-glimpse.webp'
export { default as LadybirdLandingAchievement } from './ladybird-landing.webp'
export { default as PetParadeAchievement } from './pet-parade.webp'
export { default as PlaceholderAchievement } from './placeholder.webp'
export { default as ProjectsPeruserAchievement } from './projects-peruser.webp'
export { default as RecursiveRewardAchievement } from './recursive-reward.webp'
export { default as ThemeTapdanceAchievement } from './theme-tapdance.webp'
export { default as UnknownAchievement } from './unknown.webp'
🤖 Prompt for AI Agents
In src/images/achievements/index.ts (lines 1-11) the file is an index barrel
exporting .webp assets which violates the repo guideline; remove this barrel or
replace it with a concrete aggregator module and update imports. Either delete
this index.ts and change all call sites to import the individual .webp files
directly, or rename the file to a specific module name (e.g.,
achievementImages.ts) that exports the same named assets, then search and update
all imports to reference the new module path (or the direct asset paths) so no
index barrel remains. Ensure all exports remain the same identifiers and run a
quick build to verify resolving paths.

Comment on lines +1 to +3
export { default as DraftKingsLogo } from './draftkings.webp'
export { default as NewInnovationsLogo } from './newinnov.webp'
export { default as QGendaLogo } from './qgenda.webp'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Do not use index.ts barrels in this repo

Per guidelines, replace this index.ts with a concrete module (e.g., src/images/logos.ts) or import assets directly where used. Update callers (e.g., src/lib/experience.ts) to the concrete path and remove this file.

List existing barrels to clean up:


🏁 Script executed:

#!/bin/bash
fd --glob 'index.ts' src/images -x ls -la {}

Length of output: 381


Remove index.ts barrels under src/images and replace with concrete modules

Barrel files found: src/images/projects/index.ts, src/images/pets/index.ts, src/images/achievements/index.ts, src/images/logos/index.ts, src/images/headshot/index.ts. Replace each barrel with a concrete module (e.g., src/images/logos.ts) or import assets directly where used; update callers (e.g., src/lib/experience.ts) to the concrete paths and delete these index.ts files.

import PlaceholderAchievement from '@/images/achievements/placeholder.webp'
import RecursiveRewardAchievement from '@/images/achievements/recursive-reward.webp'
import ThemeTapdanceAchievement from '@/images/achievements/theme-tapdance.webp'
import * as Images from '@/images/achievements'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid barrel import (index.ts) per repo rule

Replace @/images/achievements barrel with a concrete module path (e.g., src/images/achievements.ts) or import specific assets directly; remove the index.ts.

🤖 Prompt for AI Agents
In src/lib/achievements.ts around line 1, the code uses a barrel import "import
* as Images from '@/images/achievements'" which violates the repo rule; replace
this with a concrete module path or direct asset imports (for example import the
module file as "src/images/achievements.ts" or import specific assets like
"src/images/achievements/award.png" or "@/images/achievements/award.png"), and
remove or stop relying on the index.ts barrel export so imports reference
explicit files to enable clearer dependency tracking and tree-shaking.

import draftKingsLogo from '@/images/logos/draftkings.webp'
import newInnovationsLogo from '@/images/logos/newinnov.webp'
import qgendaLogo from '@/images/logos/qgenda.webp'
import * as Logos from '@/images/logos'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid barrel import (index.ts) per repo rule

Replace @/images/logos barrel with a concrete module path (e.g., move exports to src/images/logos.ts or import the specific assets directly) and remove the index.ts.

🤖 Prompt for AI Agents
In src/lib/experience.ts around line 1, the file currently uses a barrel import
from "@/images/logos" which violates the repo rule; replace that barrel import
with a concrete module path by either (A) creating a single module file at
src/images/logos.ts that explicitly exports the required logo assets and import
from '@/images/logos.ts', or (B) import each required asset directly from their
true file paths (e.g., '@/images/logos/logoName.svg') and then remove the
index.ts barrel file from src/images so no barrel imports remain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant