The .empty svg rule (styling the OrdersIcon/BasketIcon) was a plain descendant selector, so it also matched — and, with higher specificity than inherited color, overrode — the backdrop's own food-icon svgs nested inside the same .empty box. Scope it to a direct child (> svg) so it only targets the actual empty-state icon. Also expands the backdrop palette from 3 to 6 colors (adds basil, berry, and cocoa) for more variety across the icons. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import type { CSSProperties } from 'react'
|
|
|
|
import styles from './MenuBackdrop.module.scss'
|
|
|
|
const PizzaIcon = () => (
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M12 3 3 20h18L12 3Z" />
|
|
<path
|
|
strokeLinecap="round"
|
|
d="M4.5 17.5c2.5-1.5 4.5-1.5 7.5-.5s5 1 7.5-.5"
|
|
/>
|
|
<circle cx="10" cy="14" r="0.9" fill="currentColor" stroke="none" />
|
|
<circle cx="14.5" cy="15.5" r="0.9" fill="currentColor" stroke="none" />
|
|
</svg>
|
|
)
|
|
|
|
const BurgerIcon = () => (
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
>
|
|
<path d="M4 10c0-3 3.5-5 8-5s8 2 8 5" />
|
|
<path d="M3 10.5h18" />
|
|
<path d="M4 13.5h16" />
|
|
<path d="M3.5 16.5h17" />
|
|
<path d="M4 19c0 1 .8 1.5 2.2 1.5h11.6c1.4 0 2.2-.5 2.2-1.5" />
|
|
</svg>
|
|
)
|
|
|
|
const FriesIcon = () => (
|
|
<svg
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
>
|
|
<path d="M6 9 5 21h14l-1-12Z" />
|
|
<path d="M9 4.5v6M12 3.5v7M15 4.5v6" />
|
|
</svg>
|
|
)
|
|
|
|
const ICONS = [PizzaIcon, BurgerIcon, FriesIcon]
|
|
const ICON_COLORS = [
|
|
'#e2725b', // tomato
|
|
'#d9a441', // crust
|
|
'#e8c468', // cheese
|
|
'#7a9d6e', // basil
|
|
'#a5678f', // berry
|
|
'#8a5a44', // cocoa
|
|
]
|
|
|
|
// Fixed, hand-placed positions rather than random ones — random values would
|
|
// differ between the server-rendered and first client-rendered HTML and
|
|
// trigger a hydration mismatch. Positioned as percentages of the containing
|
|
// card, not the viewport, so this only ever covers whatever box renders it.
|
|
const PLACEMENTS = [
|
|
{ top: '10%', left: '8%', size: 32, rotate: -14, delay: 0 },
|
|
{ top: '14%', left: '82%', size: 26, rotate: 18, delay: 0.5 },
|
|
{ top: '40%', left: '20%', size: 24, rotate: 8, delay: 1.1 },
|
|
{ top: '55%', left: '80%', size: 30, rotate: -10, delay: 0.3 },
|
|
{ top: '78%', left: '14%', size: 26, rotate: 16, delay: 1.6 },
|
|
{ top: '82%', left: '58%', size: 22, rotate: -20, delay: 0.8 },
|
|
{ top: '22%', left: '48%', size: 20, rotate: 6, delay: 1.3 },
|
|
{ top: '62%', left: '44%', size: 24, rotate: -6, delay: 0.2 },
|
|
]
|
|
|
|
export const MenuBackdrop = () => (
|
|
<div className={styles.backdrop} aria-hidden="true">
|
|
{PLACEMENTS.map((placement, index) => {
|
|
const Icon = ICONS[index % ICONS.length]
|
|
const color = ICON_COLORS[index % ICON_COLORS.length]
|
|
return (
|
|
<span
|
|
key={index}
|
|
className={styles.icon}
|
|
style={
|
|
{
|
|
top: placement.top,
|
|
left: placement.left,
|
|
width: placement.size,
|
|
height: placement.size,
|
|
animationDelay: `${placement.delay}s`,
|
|
'--icon-rotate': `${placement.rotate}deg`,
|
|
color,
|
|
} as CSSProperties
|
|
}
|
|
>
|
|
<Icon />
|
|
</span>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|