Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/components/CollectionSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ const CollectionSection = () => {

return (
<section className="shop-by-collection">
<h2 className="collection-heading">
<span className="heading-shop">SHOP</span>{' '}
<span className="heading-by">BY</span>{' '}
<span className="heading-collection">COLLECTION</span>
<h2 className="section-title mb-12">
<span className="text-[#000]">SHOP </span>
<span>BY </span>
<span className="text-[#000]">COLLECTION</span>
</h2>

<div className="collection-grid">
Expand Down
93 changes: 47 additions & 46 deletions src/components/Products/ProductCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const HeartIcon = ({ isWishlisted = false, animate = false, className = 'h-6 w-6
viewBox="0 0 18 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={`${className} transition-transform duration-200 ease-out ${animate ? 'animate-double-pop' : (isWishlisted ? 'scale-110' : '')} ${isWishlisted ? 'text-white' : 'text-current'}`}
className={`${className} transition-transform duration-200 ease-out ${animate ? 'animate-double-pop' : (isWishlisted ? 'scale-110' : '')} ${isWishlisted ? 'text-white' : 'text-current'}`}
aria-hidden="true"
focusable="false"
>
Expand Down Expand Up @@ -96,20 +96,21 @@ const ProductCard = forwardRef(({ product }, ref) => {
}

return (
<div
<div
ref={ref}
className="bg-white rounded-2xl p-4 transition-all duration-300 shadow-[0_8px_30px_rgb(0,0,0,0.15)] hover:shadow-[0_8px_30px_rgb(0,0,0,0.25)] flex flex-col select-none"
className="bg-white rounded-2xl p-3 sm:p-4 transition-all duration-300 shadow-[0_8px_30px_rgb(0,0,0,0.15)] hover:shadow-[0_8px_30px_rgb(0,0,0,0.25)] flex flex-col select-none max-w-full"
>
{/* --- IMAGE CONTAINER --- */}
<div
className="relative aspect-square overflow-hidden rounded-xl mb-4 bg-gray-100 group cursor-pointer"
role="button"
tabIndex={0}
aria-label={`View details for ${product.name}`}
onClick={handleProductClick}
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ') && handleProductClick()}
>

<div
className="relative w-full overflow-hidden rounded-xl mb-3 bg-gray-100 group cursor-pointer"
style={{ paddingTop: '100%' }}
role="button"
tabIndex={0}
aria-label={`View details for ${product.name}`}
onClick={handleProductClick}
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ') && handleProductClick()}
>

{/* Badges for NEW and SALE */}
<div className="absolute top-3 left-3 z-10 flex flex-col gap-2">
{product.isNew && (
Expand All @@ -123,7 +124,7 @@ const ProductCard = forwardRef(({ product }, ref) => {
</span>
)}
</div>

{/* State 1: Image is loading */}
{!imageLoaded && !imageError && (
<div className="absolute inset-0 bg-gradient-to-br from-gray-100 to-gray-200 animate-pulse flex items-center justify-center">
Expand All @@ -146,7 +147,7 @@ const ProductCard = forwardRef(({ product }, ref) => {
<img
src={product.imageUrl || 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDMwMCAzMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMzAwIiBmaWxsPSIjRjNGNEY2Ii8+CjxwYXRoIGQ9Ik0xMjUgMTI1SDEzNVYxMzVIMTI1VjEyNVpNMTM1IDEyNUgxNDVWMTM1SDEzNVYxMjVaTTE0NSAxMjVIMTU1VjEzNUgxNDVWMTI1Wk0xNTUgMTI1SDE2NVYxMzVIMTU1VjEyNVpNMTY1IDEyNUgxNzVWMTM1SDE2NVYxMjVaIiBmaWxsPSIjOUI5QkEzIi8+CjxwYXRoIGQ9Ik0xMzUgMTQ1SDE0NVYxNTVIMTM1VjE0NVpNMTQ1IDE0NUgxNTVWMTU1SDE0NVYxNDVaTTE1NSAxNDVIMTY1VjE1NUgxNTVWMTQ1WiIgZmlsbD0iIzlCOUJBMyIvPgo8L3N2Zz4K'}
alt={product.name}
className={`w-full h-full object-contain transition-opacity duration-500 ${imageLoaded && !imageError ? 'opacity-100' : 'opacity-0'}`}
className={`absolute inset-0 w-full h-full object-cover transition-opacity duration-500 ${imageLoaded && !imageError ? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setImageLoaded(true)}
onError={() => {
setImageLoaded(true);
Expand Down Expand Up @@ -185,7 +186,7 @@ const ProductCard = forwardRef(({ product }, ref) => {
<span className="font-bold text-lg text-gray-800">{formatPrice(product.price)}</span>
</div>
</div>

<div className="mb-2">
<h3 className="font-bold text-2xl text-gray-800 leading-tight line-clamp-2">{product.name}</h3>
</div>
Expand Down Expand Up @@ -216,15 +217,15 @@ const ProductCard = forwardRef(({ product }, ref) => {
</option>
))}
</select>
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<svg className="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div className="absolute inset-y-0 right-3 flex items-center pointer-events-none">
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
)}
</div>

<div className="flex items-center gap-3 mt-auto">
<button
onClick={(e) => handleActionClick(e, handleWishlistToggle)}
Expand All @@ -238,40 +239,40 @@ const ProductCard = forwardRef(({ product }, ref) => {
<HeartIcon isWishlisted={isWishlisted} animate={animateLike} className="h-5 w-5" />
</button>

{/* --- Add to Cart Button --- */}
<button
onClick={(e) => handleActionClick(e, handleAddToCart)}
className={`
{/* --- Add to Cart Button --- */}
<button
onClick={(e) => handleActionClick(e, handleAddToCart)}
className={`
-ml-px flex-grow flex items-center justify-center gap-2
bg-[#023e8a] text-white font-medium
py-3 px-4 rounded-r-xl
hover:bg-[#1054ab] transition-colors duration-150 hover:shadow-lg cursor-pointer
focus:outline-none focus:z-10
`}
aria-live="polite"
>
{cartLoading ? (
<span className="ml-2 flex items-center gap-2 font-semibold">
<svg className="w-5 h-5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="10" strokeWidth="3" stroke="currentColor" opacity="0.25" />
<path d="M22 12a10 10 0 00-10-10" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
</svg>
<span>ADDING...</span>
</span>
) : cartAdded ? (
<span className="ml-2 flex items-center gap-2 font-semibold">
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
<span>ADDED</span>
</span>
) : (
<>
<CartIcon />
<span className="ml-2">ADD TO CART</span>
</>
)}
</button>
aria-live="polite"
>
{cartLoading ? (
<span className="ml-2 flex items-center gap-2 font-semibold">
<svg className="w-5 h-5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="10" strokeWidth="3" stroke="currentColor" opacity="0.25" />
<path d="M22 12a10 10 0 00-10-10" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
</svg>
<span>ADDING...</span>
</span>
) : cartAdded ? (
<span className="ml-2 flex items-center gap-2 font-semibold">
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<path strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
<span>ADDED</span>
</span>
) : (
<>
<CartIcon />
<span className="ml-2">ADD TO CART</span>
</>
)}
</button>

</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Products/ProductGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function ProductGrid({ products, lastProductElementRef }) {
}

return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-12">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{products.map((product, index) => {
// Attach ref to the last product for infinite scroll
const isLastProduct = index === products.length - 1;
Expand Down
17 changes: 10 additions & 7 deletions src/components/Products/SortDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const SORT_OPTIONS = [
{ label: 'Rating - High to Low', field: 'rating', order: 'desc' },
];

export default function SortDropdown({ sortBy = 'featured', sortOrder = 'desc', onSortChange = () => {} }) {
export default function SortDropdown({ sortBy = 'featured', sortOrder = 'desc', onSortChange = () => {}, className = '' }) {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);

Expand Down Expand Up @@ -50,24 +50,27 @@ export default function SortDropdown({ sortBy = 'featured', sortOrder = 'desc',
};

return (
<div className="flex items-center gap-4">
<div className="relative">
<div className={`flex items-center gap-2 sm:gap-4 ${className}`}>
<div className="relative flex-shrink-0">
<span className="font-semibold text-lg text-gray-800">Sort by:</span>
<div className="absolute -bottom-1 left-0 w-12 h-0.5 bg-gray-800" />
</div>

<div className="relative" ref={dropdownRef}>
<div className="relative flex-1 sm:flex-initial" ref={dropdownRef}>
<button
onClick={() => setIsOpen(!isOpen)}
className="flex items-center gap-2 bg-transparent text-gray-700 px-6 py-3 rounded-lg font-semibold border-2 border-gray-300 hover:border-blue-500 hover:text-blue-600 hover:bg-blue-50 transition-all duration-300"
className="w-full sm:w-[240px] flex items-center justify-between gap-2 bg-transparent text-gray-700 px-4 py-2 sm:px-6 sm:py-3 rounded-lg font-semibold border-2 border-gray-300 hover:border-blue-500 hover:text-blue-600 hover:bg-blue-50 transition-all duration-300"
aria-haspopup="true"
aria-expanded={isOpen}
>
{currentSort.label}
<span className="truncate text-left">{currentSort.label}</span>
<svg className="w-4 h-4 ml-2 text-gray-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>

{isOpen && (
<div className="absolute right-0 z-50 w-56 mt-2 origin-top-right bg-white border border-gray-200 rounded-lg shadow-xl">
<div className="absolute left-0 z-50 w-full sm:w-64 mt-2 origin-top-left sm:origin-top-right bg-white border border-gray-200 rounded-lg shadow-xl">
<div className="py-2">
{SORT_OPTIONS.map((option, index) => (
<button
Expand Down
36 changes: 19 additions & 17 deletions src/components/RecentlyViewed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const ChevronRightIcon = (props) => (
</svg>
);


export default function RecentlyViewed() {
const [items] = useState(() => getRecentlyViewed());
const [currentIndex, setCurrentIndex] = useState(0);
Expand All @@ -31,7 +30,7 @@ export default function RecentlyViewed() {
const newIndex = Math.max(currentIndex - itemsPerPage, 0);
setCurrentIndex(newIndex);
};

if (!items || items.length === 0) {
return null;
}
Expand All @@ -42,43 +41,46 @@ export default function RecentlyViewed() {
const visibleItems = items.slice(currentIndex, currentIndex + itemsPerPage);

return (
<section className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<section className="max-w-6xl mx-auto px-3 sm:px-6 lg:px-8 py-8">
{/* Header section with title and navigation arrows */}
<div className="flex items-center justify-between mb-8">
<h2 className="text-5xl lg:text-heading-xxl font-montserrat text-black leading-none uppercase text-center tracking-tight py-10 text-stroke-black">
RECENTLY
<span className="ml-5 text-[#f7faff]">VIEWED</span>
<div className="flex items-center justify-between mb-6 flex-col sm:flex-row gap-4 sm:gap-0">
<h2 className="section-title text-center w-full sm:w-auto mb-0">
<span className="text-[#000]">RECENTLY </span>
<span className="text-[#f7faff]">VIEWED</span>
</h2>

{/* Navigation Buttons */}
<div className="flex items-center gap-3">
<button
onClick={prevSlide}
disabled={!canGoPrev}
className="flex h-15 w-15 items-center justify-center rounded-full border border-gray-300 text-gray-500 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40 transition-all duration-200"
className="flex h-10 w-10 items-center justify-center rounded-full border border-gray-300 text-gray-500 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40 transition-all duration-200"
aria-label="Previous"
>
<ChevronLeftIcon className="h-5 w-5" />
</button>

<button
onClick={nextSlide}
disabled={!canGoNext}
className="flex h-15 w-15 items-center justify-center rounded-full border border-gray-300 text-gray-500 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40 transition-all duration-200"
className="flex h-10 w-10 items-center justify-center rounded-full border border-gray-300 text-gray-500 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-40 transition-all duration-200"
aria-label="Next"
>
<ChevronRightIcon className="h-5 w-5" />
</button>
</div>
</div>
{/* Recently Viewed Products Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-12 transition-all duration-500 ease-in-out">
{visibleItems.map((product) => (
<div key={product.id} className="opacity-100">
<ProductCard product={product} />
</div>
))}

{/* Recently Viewed Products: grid on desktop, horizontal scroll on mobile */}
<div className="transition-all duration-500 ease-in-out">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{visibleItems.map((product) => (
<div key={product.id} className="opacity-100">
<ProductCard product={product} />
</div>
))}
</div>
</div>
</section>
);

}
2 changes: 1 addition & 1 deletion src/components/SupplementForGoalsSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function SupplementForGoalsSection() {
return (
<section id="goals" ref={goalsRef} className="px-10 py-24 flex flex-col gap-16">
<h2 id="why-choose" className="section-title">
Supplements for <span>every</span> goal
<span className="text-[#000]">Supplements for </span><span className="text-[#f7faff]">every</span> <span className="text-[#000]">goal</span>
</h2>

<div className="space-y-10">
Expand Down
8 changes: 4 additions & 4 deletions src/components/WhyChoose.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ function WhyChoose() {
<section aria-labelledby="why-choose" className="bg-black">
<h2
id="why-choose"
className="bg-white text-4xl lg:text-heading-xxl font-montserrat font-bold leading-none uppercase text-center -tracking-widest py-16"
className="bg-white text-4xl lg:text-heading-xxl uppercase py-16 section-title"
>
Why <span className="text-white text-outline">Choose</span>
<span className="capitalize"> Core</span>
<span className="text-red-500 text-outline">X</span> Products
<span className="text-[#000]">Why </span><span>Choose</span>
<span className="capitalize text-[#000]"> Core</span>
<span className="text-red-500">X</span><span className="text-[#000]"> Products</span>
</h2>
<div className="grid grid-cols-1 gap-y-16 lg:grid-cols-3 max-w-5xl mx-auto text-white text-center py-23 leading-normal">
<div className="flex flex-col items-center space-y-2">
Expand Down
41 changes: 0 additions & 41 deletions src/components/collection.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,6 @@
padding: 85px;
}

/* Heading Styles */
.collection-heading {
text-align: center;
font-size: 64px;
font-weight: 700;
margin-bottom: 60px;
letter-spacing: -2%;
line-height: 64px;
text-transform: uppercase;
}

.heading-shop,
.heading-collection {
color: #000;
font-weight: 900;
font-family: 'Montserrat', sans-serif;
text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
}

.heading-by {
color: transparent;
-webkit-text-stroke: 1px #000;
text-stroke: 1px #000;
font-weight: 700;
padding: 0 8px;
}

/* Collection Grid */
.collection-grid {
display: grid;
Expand Down Expand Up @@ -118,10 +91,6 @@

/* Responsive Design */
@media (max-width: 1024px) {
.collection-heading {
font-size: 3rem;
}

.collection-grid {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
Expand All @@ -133,16 +102,6 @@
padding: 60px 16px;
}

.collection-heading {
font-size: 2rem;
margin-bottom: 40px;
}

.heading-by {
-webkit-text-stroke: 1.5px #000;
text-stroke: 1.5px #000;
}

.collection-grid {
grid-template-columns: 1fr;
gap: 16px;
Expand Down
Loading