Lets customers pick options on a menu item detail page before adding to the basket, and makes displayed prices respect a configurable currency/locale via VITE_CURRENCY/VITE_LOCALE. Also crossfades the basket's empty/filled states with AnimatePresence in wait mode instead of animating both at once. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
58 lines
1.3 KiB
TypeScript
58 lines
1.3 KiB
TypeScript
import type { CSSProperties } from 'react'
|
|
|
|
import styles from './MenuItemThumbnail.module.scss'
|
|
|
|
type MenuItemThumbnailProps = {
|
|
name: string
|
|
size?: 'small' | 'hero'
|
|
style?: CSSProperties
|
|
}
|
|
|
|
const UtensilsIcon = () => (
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
>
|
|
<path d="M7 3v7a2 2 0 0 0 2 2v9" />
|
|
<path d="M7 3v4M11 3v4" />
|
|
<path d="M17 3c-1.5 0-2.5 2-2.5 5s1 5 1.5 5v9" />
|
|
</svg>
|
|
)
|
|
|
|
const photoByKeyword: Array<{ keyword: string; src: string }> = [
|
|
{ keyword: 'pizza', src: '/pizza.png' },
|
|
{ keyword: 'burger', src: '/burger.png' },
|
|
]
|
|
|
|
// Falls back to a simple icon for any menu item that isn't Pizza or Burger,
|
|
// since there's no photo for it yet.
|
|
const photoFor = (name: string) => {
|
|
const lower = name.toLowerCase()
|
|
return photoByKeyword.find((entry) => lower.includes(entry.keyword))?.src
|
|
}
|
|
|
|
export const MenuItemThumbnail = ({
|
|
name,
|
|
size = 'small',
|
|
style,
|
|
}: MenuItemThumbnailProps) => {
|
|
const src = photoFor(name)
|
|
return (
|
|
<div
|
|
className={`${styles.thumbnail} ${size === 'hero' ? styles.hero : ''}`}
|
|
style={style}
|
|
aria-hidden="true"
|
|
>
|
|
{src ? (
|
|
<img src={src} alt="" className={styles.photo} />
|
|
) : (
|
|
<UtensilsIcon />
|
|
)}
|
|
</div>
|
|
)
|
|
}
|