Skip to content

Commit 7b75379

Browse files
nicklemmonclaude
andcommitted
Remove requireAsset duplication and centralize css module lookups
requireAsset was copy-pasted identically across cards.ts, item.ts, and monsters.ts; moved it into vite.ts alongside the other glob helpers. The css[key] ?? '' workaround for noUncheckedIndexedAccess was also repeated ad hoc across ~10 components; added cx()/cssClass() in helpers/css.ts to centralize the safe lookup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GzLmUWBV6CUEVjoDuTZkAF
1 parent 2af5820 commit 7b75379

14 files changed

Lines changed: 84 additions & 70 deletions

File tree

src/components/animated-deck.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { useEffect, useRef } from 'react'
22
import { motion, AnimatePresence } from 'motion/react'
3-
import { clsx } from 'clsx'
43
import { EmptyDeck } from './empty-deck'
54
import css from './deck.module.css'
65

@@ -25,7 +24,7 @@ export function AnimatedDeck({ children }: AnimatedDeckProps) {
2524
})
2625

2726
return (
28-
<div className={clsx({ [css['deck'] ?? '']: true })} data-testid="animated-deck-container">
27+
<div className={css['deck']} data-testid="animated-deck-container">
2928
{childArray.length === 0 && <EmptyDeck />}
3029
<AnimatePresence>
3130
{childArray.map((child, index) => {

src/components/button.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { clsx } from 'clsx'
1+
import { cx } from '../helpers/css'
22
import css from './button.module.css'
33

44
/** Re-usable button component */
@@ -12,10 +12,11 @@ export function Button({
1212
variant?: 'primary' | 'secondary' | 'tertiary' | 'destructive' | 'unstyled'
1313
} & React.ComponentPropsWithRef<'button'>) {
1414
const withClsx = (root: string, className?: string) => {
15-
return clsx(
15+
return cx(
16+
css,
1617
{
17-
[css[root] ?? '']: true,
18-
[css[variant] ?? '']: true,
18+
[root]: true,
19+
[variant]: true,
1920
},
2021
className,
2122
)

src/components/card.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { clsx } from 'clsx'
21
import { useState, type MouseEvent } from 'react'
32
import type { Card } from '../types/cards'
43
import cardBackImg from '../images/card-back.webp'
54
import swordIcon from '../images/sword.webp'
5+
import { cx } from '../helpers/css'
66
import { StatsRow, StatIcon, StatVal } from './stats'
77
import css from './card.module.css'
88

@@ -27,20 +27,21 @@ export function Card({
2727
const [isHovering, setIsHovering] = useState(false)
2828

2929
const withClsx = (rootClass: string | undefined, additionalClassName?: string | undefined) => {
30-
return clsx(
30+
return cx(
31+
css,
3132
{
32-
[rootClass ?? '']: true,
33-
[css['disabled'] ?? '']: status === 'disabled',
34-
[css['in-play'] ?? '']: status === 'in-play',
35-
[css['idle'] ?? '']: status === 'idle',
36-
[css['face-down'] ?? '']: orientation === 'face-down',
37-
[css['face-up'] ?? '']: orientation === 'face-up',
38-
[css['stacked'] ?? '']: isStacked === true,
39-
[css['rarity-0'] ?? '']: rarity === 0,
40-
[css['rarity-1'] ?? '']: rarity === 1,
41-
[css['rarity-2'] ?? '']: rarity === 2,
42-
[css['rarity-3'] ?? '']: rarity === 3,
33+
disabled: status === 'disabled',
34+
'in-play': status === 'in-play',
35+
idle: status === 'idle',
36+
'face-down': orientation === 'face-down',
37+
'face-up': orientation === 'face-up',
38+
stacked: isStacked === true,
39+
'rarity-0': rarity === 0,
40+
'rarity-1': rarity === 1,
41+
'rarity-2': rarity === 2,
42+
'rarity-3': rarity === 3,
4343
},
44+
rootClass,
4445
additionalClassName,
4546
)
4647
}

src/components/deck.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import React from 'react'
2-
import { clsx } from 'clsx'
32
import { EmptyDeck } from './empty-deck'
43
import css from './deck.module.css'
54

65
export function Deck({ children }: { children?: React.ReactNode }) {
76
return (
8-
<div
9-
className={clsx({
10-
[css['deck'] ?? '']: true,
11-
})}
12-
>
7+
<div className={css['deck']}>
138
{React.Children.count(children) === 0 ? (
149
<EmptyDeck />
1510
) : (

src/components/dialog.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { clsx } from 'clsx'
21
import { AnimatePresence, motion } from 'motion/react'
2+
import { cx } from '../helpers/css'
33
import css from './dialog.module.css'
44

55
export function Dialog({
@@ -11,9 +11,9 @@ export function Dialog({
1111
onClose?: () => void
1212
}) {
1313
const withStatusClsx = (root: string) =>
14-
clsx({
15-
[css[root] ?? '']: true,
16-
[css['is-open'] ?? '']: open,
14+
cx(css, {
15+
[root]: true,
16+
'is-open': open,
1717
})
1818

1919
return (

src/components/feedback.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { motion } from 'motion/react'
2-
import { clsx } from 'clsx'
2+
import { cx } from '../helpers/css'
33
import css from './feedback.module.css'
44

55
const FEEDBACK_DURATION = 1.0
@@ -34,11 +34,11 @@ export function Feedback({
3434
{...(onAnimationComplete ? { onAnimationComplete } : {})}
3535
>
3636
<div
37-
className={clsx({
38-
[css['feedback-text'] ?? '']: true,
39-
[css['neutral'] ?? '']: variant === 'neutral',
40-
[css['negative'] ?? '']: variant === 'negative',
41-
[css['positive'] ?? '']: variant === 'positive',
37+
className={cx(css, {
38+
'feedback-text': true,
39+
neutral: variant === 'neutral',
40+
negative: variant === 'negative',
41+
positive: variant === 'positive',
4242
})}
4343
>
4444
{variant === 'positive' && '+'}

src/components/item-shop-card.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { clsx } from 'clsx'
21
import { AnimatePresence, motion } from 'motion/react'
32
import type { Card as CardType } from '../types/cards'
3+
import { cx } from '../helpers/css'
44
import { PriceStatsRow } from './price-stats-row'
55
import { Card } from './card'
66
import css from './item-shop-card.module.css'
@@ -20,13 +20,14 @@ export function ItemShopCard({
2020
const disabled = shopStatus === 'unaffordable' || shopStatus === 'purchased'
2121

2222
const withClsx = (rootClass: string | undefined, className?: string | undefined) => {
23-
return clsx(
23+
return cx(
24+
css,
2425
{
25-
[rootClass ?? '']: true,
26-
[css['purchased'] ?? '']: shopStatus === 'purchased',
27-
[css['unaffordable'] ?? '']: shopStatus === 'unaffordable',
28-
[css['affordable'] ?? '']: shopStatus === 'affordable',
26+
purchased: shopStatus === 'purchased',
27+
unaffordable: shopStatus === 'unaffordable',
28+
affordable: shopStatus === 'affordable',
2929
},
30+
rootClass,
3031
className,
3132
)
3233
}

src/components/item-shop-item.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { clsx } from 'clsx'
21
import { AnimatePresence, motion } from 'motion/react'
2+
import { cx } from '../helpers/css'
33
import { PriceStatsRow } from './price-stats-row'
44
import type { Item } from '../types/items'
55
import css from './item-shop-item.module.css'
@@ -20,12 +20,13 @@ export function ItemShopItem({
2020
className?: string | undefined
2121
}) {
2222
const withClsx = (rootClass: string | undefined, className?: string | undefined) => {
23-
return clsx(
23+
return cx(
24+
css,
2425
{
25-
[rootClass ?? '']: true,
26-
[css['unaffordable'] ?? '']: shopStatus === 'unaffordable',
27-
[css['affordable'] ?? '']: shopStatus === 'affordable',
26+
unaffordable: shopStatus === 'unaffordable',
27+
affordable: shopStatus === 'affordable',
2828
},
29+
rootClass,
2930
className,
3031
)
3132
}

src/components/stack.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { clsx } from 'clsx'
22
import type { Spacing } from '../types/tokens'
3+
import { cssClass } from '../helpers/css'
34
import css from './stack.module.css'
45

56
const ALIGN_PROP_VALS = ['left', 'right', 'center'] as const
67

78
type AlignProp = (typeof ALIGN_PROP_VALS)[number]
89

910
const ALIGN_CLASS_MAP: Record<AlignProp, string> = {
10-
left: css['left'] ?? '',
11-
right: css['right'] ?? '',
12-
center: css['center'] ?? '',
11+
left: cssClass(css, 'left'),
12+
right: cssClass(css, 'right'),
13+
center: cssClass(css, 'center'),
1314
}
1415

1516
export function Stack({

src/helpers/cards.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Card } from '../types/cards'
22
import { getSound } from './get-sound'
3+
import { requireAsset } from './vite'
34

45
/** Defines a card config. */
56
export function defineCard(config: Omit<Card, 'id' | 'artwork' | 'sfx'>) {
@@ -18,13 +19,6 @@ export function requireCard(id: string, deck: readonly Card[]): Card {
1819
return card
1920
}
2021

21-
/** Gets a required asset. Throws when the asset is missing. */
22-
function requireAsset(assets: Record<string, string | undefined>, path: string): string {
23-
const asset = assets[path]
24-
if (!asset) throw new Error(`Missing required asset: ${path}`)
25-
return asset
26-
}
27-
2822
const CARD_CONFIG_MODULES = import.meta.glob<Omit<Card, 'id' | 'artwork' | 'sfx'>>(
2923
'../cards/**/config.ts',
3024
{

0 commit comments

Comments
 (0)