Remove the food-icon backdrop, back to a plain empty state
Drop MenuBackdrop entirely and put the icon, title, text, and CTA directly back on the empty state's own solid background — no separate overlay card needed once there's no pattern behind it to cover up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
.backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
filter: blur(3px) grayscale(1);
|
||||
opacity: 0.6;
|
||||
background-repeat: repeat;
|
||||
background-size: 340px 340px;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import styles from './MenuBackdrop.module.scss'
|
||||
|
||||
// Rendered once as a tiny repeating SVG tile (not as individual DOM icons)
|
||||
// set as a CSS background-image, rather than one element per icon.
|
||||
const pizza = (color: string) => `
|
||||
<path d="M12 3 3 20h18L12 3Z" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4.5 17.5c2.5-1.5 4.5-1.5 7.5-.5s5 1 7.5-.5" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" />
|
||||
<circle cx="10" cy="14" r="0.9" fill="${color}" />
|
||||
<circle cx="14.5" cy="15.5" r="0.9" fill="${color}" />
|
||||
`
|
||||
|
||||
const burger = (color: string) => `
|
||||
<path d="M4 10c0-3 3.5-5 8-5s8 2 8 5" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M3 10.5h18" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4 13.5h16" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M3.5 16.5h17" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4 19c0 1 .8 1.5 2.2 1.5h11.6c1.4 0 2.2-.5 2.2-1.5" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
`
|
||||
|
||||
const fries = (color: string) => `
|
||||
<path d="M6 9 5 21h14l-1-12Z" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M9 4.5v6M12 3.5v7M15 4.5v6" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
`
|
||||
|
||||
const ICON_VARIANTS = [pizza, burger, fries]
|
||||
const ICON_COLORS = [
|
||||
'#e2725b', // tomato
|
||||
'#d9a441', // crust
|
||||
'#e8c468', // cheese
|
||||
'#7a9d6e', // basil
|
||||
'#a5678f', // berry
|
||||
'#8a5a44', // cocoa
|
||||
]
|
||||
|
||||
// One icon centered in each grid cell within the tile, so they line up
|
||||
// evenly instead of clustering.
|
||||
const TILE_SIZE = 240
|
||||
const GRID_COLS = 4
|
||||
const GRID_ROWS = 4
|
||||
const CELL_WIDTH = TILE_SIZE / GRID_COLS
|
||||
const CELL_HEIGHT = TILE_SIZE / GRID_ROWS
|
||||
const ICON_SIZE = 30
|
||||
const ICON_SCALE = ICON_SIZE / 24
|
||||
|
||||
const buildTileSvg = () => {
|
||||
const instances = Array.from(
|
||||
{ length: GRID_COLS * GRID_ROWS },
|
||||
(_, index) => {
|
||||
const col = index % GRID_COLS
|
||||
const row = Math.floor(index / GRID_COLS)
|
||||
const x = col * CELL_WIDTH + CELL_WIDTH / 2
|
||||
const y = row * CELL_HEIGHT + CELL_HEIGHT / 2
|
||||
const rotate = ((index * 29) % 48) - 24
|
||||
const color = ICON_COLORS[index % ICON_COLORS.length]
|
||||
const icon = ICON_VARIANTS[index % ICON_VARIANTS.length](color)
|
||||
const transform = `translate(${x.toFixed(1)} ${y.toFixed(1)}) rotate(${rotate}) scale(${ICON_SCALE.toFixed(3)}) translate(-12 -12)`
|
||||
return `<g transform="${transform}">${icon}</g>`
|
||||
},
|
||||
).join('')
|
||||
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${TILE_SIZE}" height="${TILE_SIZE}" viewBox="0 0 ${TILE_SIZE} ${TILE_SIZE}">${instances}</svg>`
|
||||
}
|
||||
|
||||
const TILE_DATA_URL = `data:image/svg+xml,${encodeURIComponent(buildTileSvg())}`
|
||||
|
||||
export const MenuBackdrop = () => (
|
||||
<div
|
||||
className={styles.backdrop}
|
||||
aria-hidden="true"
|
||||
style={{ backgroundImage: `url("${TILE_DATA_URL}")` }}
|
||||
/>
|
||||
)
|
||||
@@ -22,8 +22,6 @@
|
||||
}
|
||||
|
||||
.empty {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -33,15 +31,12 @@
|
||||
border: 1px dashed $color-border;
|
||||
border-radius: $radius;
|
||||
background: $color-surface;
|
||||
overflow: hidden;
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
animation: empty-state-enter 0.32s cubic-bezier(0.2, 0, 0, 1) both;
|
||||
}
|
||||
|
||||
// Direct child only — a plain descendant selector would also catch the
|
||||
// backdrop's own icons (see MenuBackdrop), overriding their per-icon color.
|
||||
> svg {
|
||||
svg {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
margin-bottom: $space-2;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { MenuBackdrop } from '#/components/ordering/MenuBackdrop.tsx'
|
||||
import type { CustomerOrderSummary } from '#/domain/ordering.ts'
|
||||
import { formatPrice } from '#/lib/format.ts'
|
||||
|
||||
@@ -65,7 +64,6 @@ export const OrdersListView = ({ orders }: OrdersListViewProps) => {
|
||||
<h1 className={styles.heading}>Your orders</h1>
|
||||
{displayedOrders.length === 0 ? (
|
||||
<div className={styles.empty}>
|
||||
<MenuBackdrop />
|
||||
<OrdersIcon />
|
||||
<p className={styles.emptyTitle}>No orders yet</p>
|
||||
<p className={styles.emptyText}>
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
}
|
||||
|
||||
.empty {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -31,11 +29,8 @@
|
||||
border: 1px dashed $color-border;
|
||||
border-radius: $radius;
|
||||
background: $color-surface;
|
||||
overflow: hidden;
|
||||
|
||||
// Direct child only — a plain descendant selector would also catch the
|
||||
// backdrop's own icons (see MenuBackdrop), overriding their per-icon color.
|
||||
> svg {
|
||||
svg {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
margin-bottom: $space-2;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'
|
||||
|
||||
import { BasketIcon } from '#/components/basket/BasketLink.tsx'
|
||||
import { CheckoutSection } from '#/components/ordering/CheckoutSection.tsx'
|
||||
import { MenuBackdrop } from '#/components/ordering/MenuBackdrop.tsx'
|
||||
import { AnimatedNumber } from '#/components/ui/AnimatedNumber.tsx'
|
||||
import type { MenuItemWithRecipe } from '#/domain/ordering.ts'
|
||||
import { useBasket } from '#/lib/basket.tsx'
|
||||
@@ -72,7 +71,6 @@ const BasketPage = () => {
|
||||
exit={{ opacity: 0 }}
|
||||
transition={transition}
|
||||
>
|
||||
<MenuBackdrop />
|
||||
<BasketIcon />
|
||||
<p className={styles.emptyTitle}>Your basket is empty</p>
|
||||
<p className={styles.emptyText}>
|
||||
|
||||
Reference in New Issue
Block a user