Skip to content

Commit ce04df4

Browse files
Add dermocosmetic brand icons
Introduce DermoBrands component rendering a grid of brand squares (Eucerin, La Roche-Posay, CeraVe, Bioderma, Vichy, Sesderma, COSRX) linking to shop filters, and inject into homepage after USP bar. X-Lovable-Edit-ID: edt-f0bcc15c-50ea-4bb6-95c7-87a1c1c1f38b Co-authored-by: asperpharma <252395498+asperpharma@users.noreply.github.com>
2 parents d87aa71 + 051a602 commit ce04df4

3 files changed

Lines changed: 133 additions & 2 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { Link } from "react-router-dom";
2+
import { motion } from "framer-motion";
3+
import { Badge } from "@/components/ui/badge";
4+
import { Stethoscope } from "lucide-react";
5+
6+
/**
7+
* Priority dermocosmetic brands — each square links to /shop?brand=<name>
8+
*/
9+
10+
const DERMO_BRANDS = [
11+
{
12+
name: "Eucerin",
13+
slug: "Eucerin",
14+
color: "from-[hsl(210,60%,95%)] to-[hsl(210,50%,88%)]",
15+
accent: "hsl(210,60%,40%)",
16+
initials: "Eu",
17+
},
18+
{
19+
name: "La Roche-Posay",
20+
slug: "La Roche-Posay",
21+
color: "from-[hsl(200,40%,94%)] to-[hsl(200,35%,86%)]",
22+
accent: "hsl(200,50%,35%)",
23+
initials: "LRP",
24+
},
25+
{
26+
name: "CeraVe",
27+
slug: "CeraVe",
28+
color: "from-[hsl(195,45%,93%)] to-[hsl(195,40%,85%)]",
29+
accent: "hsl(195,55%,35%)",
30+
initials: "CV",
31+
},
32+
{
33+
name: "Bioderma",
34+
slug: "Bioderma",
35+
color: "from-[hsl(340,40%,95%)] to-[hsl(340,35%,88%)]",
36+
accent: "hsl(340,50%,40%)",
37+
initials: "Bd",
38+
},
39+
{
40+
name: "Vichy",
41+
slug: "Vichy",
42+
color: "from-[hsl(160,35%,93%)] to-[hsl(160,30%,85%)]",
43+
accent: "hsl(160,45%,30%)",
44+
initials: "Vi",
45+
},
46+
{
47+
name: "Sesderma",
48+
slug: "Sesderma",
49+
color: "from-[hsl(35,50%,94%)] to-[hsl(35,45%,86%)]",
50+
accent: "hsl(35,55%,35%)",
51+
initials: "Sd",
52+
},
53+
{
54+
name: "COSRX",
55+
slug: "COSRX",
56+
color: "from-[hsl(0,0%,95%)] to-[hsl(0,0%,88%)]",
57+
accent: "hsl(0,0%,25%)",
58+
initials: "CX",
59+
},
60+
];
61+
62+
export default function DermoBrands() {
63+
return (
64+
<section className="py-16 sm:py-20 bg-background">
65+
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
66+
{/* Header */}
67+
<div className="text-center mb-10">
68+
<Badge
69+
variant="outline"
70+
className="mb-4 border-accent text-accent font-body text-xs tracking-[0.2em] px-4 py-1.5"
71+
>
72+
<Stethoscope className="h-3 w-3 mr-2" />
73+
DERMOCOSMETICS
74+
</Badge>
75+
<h2 className="font-heading text-2xl sm:text-3xl lg:text-4xl font-bold text-foreground">
76+
Trusted <span className="text-primary">Clinical Brands</span>
77+
</h2>
78+
<p className="mt-3 text-muted-foreground text-sm sm:text-base max-w-xl mx-auto font-body">
79+
Pharmacist-approved dermocosmetic brands — tap to explore.
80+
</p>
81+
</div>
82+
83+
{/* Brand Grid */}
84+
<div className="grid grid-cols-3 sm:grid-cols-4 lg:grid-cols-7 gap-4">
85+
{DERMO_BRANDS.map((brand, i) => (
86+
<motion.div
87+
key={brand.slug}
88+
initial={{ opacity: 0, y: 16 }}
89+
whileInView={{ opacity: 1, y: 0 }}
90+
viewport={{ once: true }}
91+
transition={{ delay: i * 0.06, duration: 0.4 }}
92+
>
93+
<Link
94+
to={`/shop?brand=${encodeURIComponent(brand.slug)}`}
95+
className="group flex flex-col items-center gap-3"
96+
>
97+
{/* Square icon */}
98+
<div
99+
className={`relative w-full aspect-square rounded-2xl bg-gradient-to-br ${brand.color} border border-border/60 group-hover:border-accent/50 group-hover:shadow-[0_4px_20px_hsl(var(--accent)/0.15)] transition-all duration-300 flex items-center justify-center overflow-hidden`}
100+
>
101+
{/* Brand initials as elegant monogram */}
102+
<span
103+
className="text-2xl sm:text-3xl lg:text-4xl font-heading font-bold tracking-tight transition-transform duration-300 group-hover:scale-110"
104+
style={{ color: brand.accent }}
105+
>
106+
{brand.initials}
107+
</span>
108+
109+
{/* Subtle shine on hover */}
110+
<div className="absolute inset-0 bg-gradient-to-tr from-transparent via-white/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
111+
</div>
112+
113+
{/* Brand name */}
114+
<span className="text-xs sm:text-sm font-body font-medium text-muted-foreground group-hover:text-foreground transition-colors text-center leading-tight">
115+
{brand.name}
116+
</span>
117+
</Link>
118+
</motion.div>
119+
))}
120+
</div>
121+
</div>
122+
</section>
123+
);
124+
}

src/lib/__tests__/antigravityFeatureFlag.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { describe, it, expect, vi, afterEach } from "vitest";
88
*/
99

1010
/** Helper type for patching globalThis.window in tests. */
11-
type GlobalWithWindow = typeof globalThis & { window?: unknown };
11+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
12+
type GlobalWithWindow = typeof globalThis & { window?: any };
1213

1314
describe("FEATURE_ANTIGRAVITY flag", () => {
1415
it("defaults to false when VITE_FEATURE_ANTIGRAVITY env var is absent", async () => {
@@ -38,7 +39,7 @@ describe("runAntigravityDiagnostic()", () => {
3839
const originalWindowProcess = (globalThis as GlobalWithWindow & { window?: { process?: unknown } }).window?.process;
3940

4041
// Set up a window object without a .process property
41-
(globalThis as GlobalWithWindow).window = {};
42+
(globalThis as GlobalWithWindow).window = {} as unknown;
4243

4344
vi.stubEnv("VITE_FEATURE_ANTIGRAVITY", "true");
4445
vi.resetModules();

src/pages/Index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const FloatingSocials = lazy(() =>
5353
default: m.FloatingSocials,
5454
}))
5555
);
56+
const DermoBrands = lazy(() => import("@/components/home/DermoBrands"));
5657

5758
// Lightweight skeleton for lazy sections
5859
const SectionSkeleton = ({ height = "h-64" }: { height?: string }) => (
@@ -167,6 +168,11 @@ const Index = () => {
167168
{/* 2. USP Bar — Trust Signals */}
168169
<USPBar />
169170

171+
{/* 2.5. Dermocosmetic Brands — Clickable Squares */}
172+
<Suspense fallback={<SectionSkeleton height="h-48" />}>
173+
<DermoBrands />
174+
</Suspense>
175+
170176
{/* 3. Product Slider — Just Landed / What's New */}
171177
<ProductSlider
172178
title={{ en: "Just Landed! What's New", ar: "وصل حديثاً! الجديد لدينا" }}

0 commit comments

Comments
 (0)