This commit is contained in:
Hamed
2026-08-03 14:48:01 +04:00
parent 37d2d8dcf0
commit 5594c3c25b
5 changed files with 125 additions and 117 deletions
+108 -105
View File
@@ -3,121 +3,124 @@
// کارت نمایش هر دستگاه داخل ویترین: شامل جلوه اسپات‌لایت (هاور روی عکس دستگاه رنگ جایگزین را نشان می‌دهد)،
// آیتم‌های شناور، گیف+توضیحات، و دکمه‌های افزودن به سبد / مشاهده سریع / علاقه‌مندی.
import { useRef, useState } from 'react';
import { Button, Tooltip, message } from 'antd';
import { ShoppingCartOutlined, EyeOutlined, HeartOutlined, HeartFilled } from '@ant-design/icons';
import { useDispatch } from 'react-redux';
import { addToCart } from '@/store/cartSlice';
import { useLanguage } from '@/app/context/LanguageContext';
import {useRef, useState} from 'react';
import {Button, Tooltip, message} from 'antd';
import {ShoppingCartOutlined, EyeOutlined, HeartOutlined, HeartFilled} from '@ant-design/icons';
import {useDispatch} from 'react-redux';
import {addToCart} from '@/store/cartSlice';
import {useLanguage} from '@/app/context/LanguageContext';
import FloatingItems from './FloatingItems';
import { floatingSnacks } from '@/data/content';
import {floatingSnacks} from '@/data/content';
export default function VendingCard({ machine, onQuickView }) {
const dispatch = useDispatch();
const { t, dir } = useLanguage();
const [wishlisted, setWishlisted] = useState(false);
const stageRef = useRef(null);
const lensRef = useRef(null);
const revealRef = useRef(null);
export default function VendingCard({machine, onQuickView}) {
const dispatch = useDispatch();
const {t, dir} = useLanguage();
const [wishlisted, setWishlisted] = useState(false);
const stageRef = useRef(null);
const lensRef = useRef(null);
const revealRef = useRef(null);
const handleMouseMove = (e) => {
const stage = stageRef.current;
if (!stage) return;
const rect = stage.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const handleMouseMove = (e) => {
const stage = stageRef.current;
if (!stage) return;
const rect = stage.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (lensRef.current) {
lensRef.current.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`;
}
if (revealRef.current) {
revealRef.current.style.clipPath = `circle(95px at ${x}px ${y}px)`;
}
};
if (lensRef.current) {
lensRef.current.style.transform = `translate(${x}px, ${y}px) translate(-50%, -50%)`;
}
if (revealRef.current) {
revealRef.current.style.clipPath = `circle(95px at ${x}px ${y}px)`;
}
};
const handleMouseLeave = () => {
if (revealRef.current) revealRef.current.style.clipPath = 'circle(0px at 50% 50%)';
};
const handleMouseLeave = () => {
if (revealRef.current) revealRef.current.style.clipPath = 'circle(0px at 50% 50%)';
};
const handleAddToCart = () => {
dispatch(
addToCart({
id: machine.id,
name: machine.name,
priceNumeric: machine.priceNumeric,
priceLabel: machine.priceLabel,
image: machine.image,
})
);
message.success(t.cart.addToast(machine.name));
};
const handleAddToCart = () => {
dispatch(
addToCart({
id: machine.id,
name: machine.name,
priceNumeric: machine.priceNumeric,
priceLabel: machine.priceLabel,
image: machine.image,
})
);
message.success(t.cart.addToast(machine.name));
};
return (
<div className="horizontal-panel flex items-center justify-center px-6 md:px-16" dir={dir}>
<div className="relative z-10 max-w-6xl w-full grid md:grid-cols-2 gap-10 items-center">
<div
ref={stageRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
className="spotlight-stage relative h-[420px] md:h-[560px] flex items-center justify-center"
>
<FloatingItems items={floatingSnacks} />
return (
<div className="horizontal-panel flex items-center justify-center px-6 md:px-16" dir={dir}>
<div className="relative z-10 max-w-6xl w-full grid md:grid-cols-2 gap-0 md:gap-10 items-center">
<div
ref={stageRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
className="spotlight-stage relative h-48 md:h-[500px] flex items-center justify-center"
>
<FloatingItems items={floatingSnacks}/>
<img src={machine.image} alt={machine.name} className="base-layer z-10" />
<img
ref={revealRef}
src={machine.imageAlt}
alt={`${machine.name} - ${t.machineActions.altVariant}`}
className="reveal-layer z-20"
/>
<div ref={lensRef} className="spotlight-lens" />
<img src={machine.image} alt={machine.name} className="base-layer z-10"/>
<img
ref={revealRef}
src={machine.imageAlt}
alt={`${machine.name} - ${t.machineActions.altVariant}`}
className="reveal-layer z-20"
/>
<div ref={lensRef} className="spotlight-lens"/>
<span className="absolute top-3 z-30 text-[11px] px-3 py-1 rounded-full bg-brand/15 border border-subtle text-brand-400 start-3">
<span
className="absolute hidden md:block top-3 z-30 text-[11px] px-3 py-1 rounded-full bg-brand/15 border border-subtle text-brand-400 start-3">
{t.machineActions.hoverHint}
</span>
</div>
<div className="flex flex-col justify-center items-center gap-5 ">
<span className="text-brand-400 text-sm font-semibold tracking-wide">{machine.shortLabel}</span>
<h3 className="text-2xl md:text-4xl font-extrabold text-primary">{machine.name}</h3>
<div
className="grid grid-cols-[auto,1fr] gap-4 items-start bg-surface border border-subtle rounded-2xl p-4">
<img
src={machine.gif}
alt={t.machineActions.gifAlt(machine.name)}
className="w-28 h-14 md:w-32 md:h-24 object-cover rounded-lg border border-subtle"
/>
<p className="text-sm md:text-base text-secondary md:leading-7">{machine.description}</p>
</div>
<ul className="flex flex-wrap gap-2">
{machine.highlights.map((h) => (
<li key={h}
className="text-xs md:text-sm text-brand-400 bg-brand/10 border border-subtle rounded-full px-3 py-1">
{h}
</li>
))}
</ul>
<p className="text-xl md:text-2xl font-bold text-primary mt-2">{machine.priceLabel}</p>
<div className="flex flex-wrap items-center gap-2 mt-2 ">
<Button type="primary" size="large" icon={<ShoppingCartOutlined/>} onClick={handleAddToCart}>
{t.machineActions.addToCart}
</Button>
<Button size="large" icon={<EyeOutlined/>} onClick={() => onQuickView?.(machine)}>
{t.machineActions.quickView}
</Button>
{/*<Tooltip title={wishlisted ? t.machineActions.wishlistRemove : t.machineActions.wishlistAdd}>*/}
{/* <Button*/}
{/* size="large"*/}
{/* shape="circle"*/}
{/* icon={wishlisted ? <HeartFilled className="text-brand-400"/> : <HeartOutlined/>}*/}
{/* onClick={() => setWishlisted((v) => !v)}*/}
{/* />*/}
{/*</Tooltip>*/}
</div>
</div>
</div>
</div>
<div className="flex flex-col gap-5">
<span className="text-brand-400 text-sm font-semibold tracking-wide">{machine.shortLabel}</span>
<h3 className="text-2xl md:text-4xl font-extrabold text-primary">{machine.name}</h3>
<div className="grid grid-cols-[auto,1fr] gap-4 items-start bg-surface border border-subtle rounded-2xl p-4">
<img
src={machine.gif}
alt={t.machineActions.gifAlt(machine.name)}
className="w-28 h-20 md:w-32 md:h-24 object-cover rounded-lg border border-subtle"
/>
<p className="text-sm md:text-base text-secondary leading-7">{machine.description}</p>
</div>
<ul className="flex flex-wrap gap-2">
{machine.highlights.map((h) => (
<li key={h} className="text-xs md:text-sm text-brand-400 bg-brand/10 border border-subtle rounded-full px-3 py-1">
{h}
</li>
))}
</ul>
<p className="text-xl md:text-2xl font-bold text-primary mt-2">{machine.priceLabel}</p>
<div className="flex flex-wrap items-center gap-3 mt-2">
<Button type="primary" size="large" icon={<ShoppingCartOutlined />} onClick={handleAddToCart}>
{t.machineActions.addToCart}
</Button>
<Button size="large" icon={<EyeOutlined />} onClick={() => onQuickView?.(machine)}>
{t.machineActions.quickView}
</Button>
<Tooltip title={wishlisted ? t.machineActions.wishlistRemove : t.machineActions.wishlistAdd}>
<Button
size="large"
shape="circle"
icon={wishlisted ? <HeartFilled className="text-brand-400" /> : <HeartOutlined />}
onClick={() => setWishlisted((v) => !v)}
/>
</Tooltip>
</div>
</div>
</div>
</div>
);
);
}