From c5631a60112d5e4393db85db4628ae9857894e92 Mon Sep 17 00:00:00 2001 From: Aravind Date: Mon, 20 Jul 2026 16:37:54 +0530 Subject: [PATCH] product feature grid --- src/app/platform/page.tsx | 22 +- src/components/platform/ConsumerFeatures.tsx | 118 ++++ src/components/platform/FeatureCard.tsx | 70 +++ src/components/platform/FeatureGrid.tsx | 98 ++++ src/components/platform/PhoneMockup.tsx | 524 ++++++++++++++++++ .../platform/ProductFeatureGrid.tsx | 71 ++- 6 files changed, 846 insertions(+), 57 deletions(-) create mode 100644 src/components/platform/ConsumerFeatures.tsx create mode 100644 src/components/platform/FeatureCard.tsx create mode 100644 src/components/platform/FeatureGrid.tsx create mode 100644 src/components/platform/PhoneMockup.tsx diff --git a/src/app/platform/page.tsx b/src/app/platform/page.tsx index 5f8fc82..a5461be 100644 --- a/src/app/platform/page.tsx +++ b/src/app/platform/page.tsx @@ -4,6 +4,7 @@ import { PlatformHero } from "@/components/platform/PlatformHero"; import { PlatformArchitecture } from "@/components/platform/PlatformArchitecture"; import { ProductFeatureGrid } from "@/components/platform/ProductFeatureGrid"; import { ProductLLMWorkflow } from "@/components/platform/ProductLLMWorkflow"; +import { ConsumerFeatures } from "@/components/platform/ConsumerFeatures"; import { CTABanner } from "@/components/ui/CTABanner"; export const metadata: Metadata = { @@ -30,17 +31,6 @@ const MERCHANT_OS = [ { icon: "dashboard", title: "Store Dashboard", desc: "Run the whole store from one simple screen." }, ]; -const CONSUMER_OS = [ - { icon: "explore", title: "Local Discovery", desc: "Find the stores and products right around you." }, - { icon: "photo_camera", title: "Camera Search", desc: "Point your camera to find a product nearby." }, - { icon: "favorite", title: "Favorites", desc: "Save the stores and items you buy again and again." }, - { icon: "storefront", title: "Nearby Stores", desc: "Shop shops within walking distance, not warehouses." }, - { icon: "shopping_bag", title: "Pickup", desc: "Order ahead and grab it on your way past." }, - { icon: "local_shipping", title: "Delivery", desc: "Short, local trips from the store to your door." }, - { icon: "redeem", title: "Rewards", desc: "Earn as you shop your neighbourhood." }, - { icon: "history", title: "Fast Reordering", desc: "Re-buy your usuals in a single tap." }, -]; - export default function PlatformPage() { return ( @@ -57,15 +47,7 @@ export default function PlatformPage() { footnote="AI Catalog powered by ProductLLM." /> - + { + switch (cardIndex) { + case 0: // Discover Nearby Stores + case 4: // Favorites + return 0; // Nearby Stores Screen + case 1: // Camera Search + return 1; // Product Search Screen + case 3: // Rewards + return 2; // Rewards Screen + case 2: // Pickup & Delivery + case 5: // Quick Reordering + return 3; // Orders Screen + default: + return 0; + } +}; + +export function ConsumerFeatures() { + const reduce = useReducedMotion(); + const [activeScreen, setActiveScreen] = useState(0); + const [hoveredCardIndex, setHoveredCardIndex] = useState(null); + + // Auto-cycling when no card is hovered + useEffect(() => { + if (reduce || hoveredCardIndex !== null) return; + + const interval = setInterval(() => { + setActiveScreen((prev) => (prev + 1) % 4); + }, 4500); // Cycle screen every 4.5 seconds + + return () => clearInterval(interval); + }, [hoveredCardIndex, reduce]); + + // Handle card hover updates + const handleHoverCard = (index: number | null) => { + setHoveredCardIndex(index); + if (index !== null) { + setActiveScreen(getScreenFromCardIndex(index)); + } + }; + + // Determine active card highlighted in grid (reflecting current active screen when not hovering) + const activeCardIndex = + hoveredCardIndex !== null + ? hoveredCardIndex + : activeScreen === 0 + ? 0 + : activeScreen === 1 + ? 1 + : activeScreen === 2 + ? 3 + : activeScreen === 3 + ? 2 + : 0; + + return ( +
+
+ {/* Header Block (Mirrors the MerchantOS header styling) */} + + + ConsumerOS + + + How the neighbourhood shops + + + Discovery, search, ordering, and rewards — the app that brings local customers to nearby stores. + + + + {/* Dynamic Showcase Grid */} +
+ {/* LEFT SIDE: Smartphone mockup */} +
+ +
+ + {/* RIGHT SIDE: Feature list grid */} +
+ +
+
+
+
+ ); +} diff --git a/src/components/platform/FeatureCard.tsx b/src/components/platform/FeatureCard.tsx new file mode 100644 index 0000000..a8f151b --- /dev/null +++ b/src/components/platform/FeatureCard.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { motion } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; + +type FeatureCardProps = { + icon: string; + title: string; + description: string; + isActive: boolean; + onHoverStart: () => void; + onHoverEnd: () => void; +}; + +export function FeatureCard({ + icon, + title, + description, + isActive, + onHoverStart, + onHoverEnd, +}: FeatureCardProps) { + // Entrance animations are orchestrated by FeatureGrid, but we manage our interactive transitions here + return ( +
+ {/* Accent glow on card hover or active */} +
+ +
+ {/* Purple circular icon */} +
+ +
+ + {/* Text details */} +
+

+ {title} +

+

+ {description} +

+
+
+
+ ); +} diff --git a/src/components/platform/FeatureGrid.tsx b/src/components/platform/FeatureGrid.tsx new file mode 100644 index 0000000..c3af9e8 --- /dev/null +++ b/src/components/platform/FeatureGrid.tsx @@ -0,0 +1,98 @@ +"use client"; + +import { motion } from "framer-motion"; +import { FeatureCard } from "./FeatureCard"; + +type Feature = { + icon: string; + title: string; + description: string; +}; + +const FEATURES: Feature[] = [ + { + icon: "explore", + title: "Discover Nearby Stores", + description: "Find trusted local businesses around you.", + }, + { + icon: "photo_camera", + title: "Camera Search", + description: "Scan products and instantly find nearby availability.", + }, + { + icon: "local_shipping", + title: "Pickup & Delivery", + description: "Choose how you want to receive your order.", + }, + { + icon: "redeem", + title: "Rewards", + description: "Earn points every time you support local businesses.", + }, + { + icon: "favorite", + title: "Favorites", + description: "Save your preferred stores and products.", + }, + { + icon: "history", + title: "Quick Reordering", + description: "Buy your regular products again in seconds.", + }, +]; + +type FeatureGridProps = { + activeCardIndex: number | null; + setActiveCardIndex: (index: number | null) => void; +}; + +// Animation variants for staggered fade-up on scroll +const containerVariants = { + hidden: {}, + visible: { + transition: { + staggerChildren: 0.1, + }, + }, +}; + +const itemVariants = { + hidden: { + opacity: 0, + y: 25, + }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.6, + ease: [0.22, 1, 0.36, 1], + }, + }, +}; + +export function FeatureGrid({ activeCardIndex, setActiveCardIndex }: FeatureGridProps) { + return ( + + {FEATURES.map((feature, idx) => ( + + setActiveCardIndex(idx)} + onHoverEnd={() => setActiveCardIndex(null)} + /> + + ))} + + ); +} diff --git a/src/components/platform/PhoneMockup.tsx b/src/components/platform/PhoneMockup.tsx new file mode 100644 index 0000000..33e85b4 --- /dev/null +++ b/src/components/platform/PhoneMockup.tsx @@ -0,0 +1,524 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { MaterialIcon } from "@/components/ui/MaterialIcon"; + +type PhoneMockupProps = { + activeScreen: number; +}; + +export function PhoneMockup({ activeScreen }: PhoneMockupProps) { + // Screens definitions + const screens = [ + // 0: Nearby Stores + { + id: "nearby-stores", + content: ( +
+ {/* Header */} +
+
+ + R.S. Puram, Coimbatore + +
+
+ nearle +
+ + +
+
+
+ + {/* Search bar */} +
+
+ + Search stores & products... +
+
+ + {/* Categories */} +
+
+ {[ + { name: "Sweets", active: true }, + { name: "Grocery", active: false }, + { name: "Veggies", active: false }, + { name: "Bakery", active: false }, + ].map((cat, idx) => ( + + {cat.name} + + ))} +
+
+ + {/* Stores List */} +
+ {[ + { + name: "Sri Krishna Sweets", + rating: "4.8", + distance: "300m away", + desc: "Mysore Pak, Laddu & Savouries", + imgBg: "bg-purple-100", + imgText: "🍰", + }, + { + name: "Organic Greens Store", + rating: "4.9", + distance: "600m away", + desc: "Fresh Farm Spinach & Organic Veggies", + imgBg: "bg-emerald-100", + imgText: "🥬", + }, + { + name: "A1 Biryani House", + rating: "4.7", + distance: "850m away", + desc: "Local Spiced Biryani & Kebabs", + imgBg: "bg-orange-100", + imgText: "🍗", + }, + ].map((store, i) => ( +
+
+ {store.imgText} +
+
+
+

+ {store.name} +

+ + ★ {store.rating} + +
+

{store.desc}

+ + {store.distance} + +
+
+ ))} +
+ + {/* Bottom Navigation Bar */} +
+
+ + Explore +
+
+ + Favorites +
+
+ + Rewards +
+
+ + Orders +
+
+
+ ), + }, + // 1: Product Search (Camera scanning) + { + id: "product-search", + content: ( +
+ {/* Header */} +
+ Camera Search +
+ +
+
+ + {/* Scanning frame area */} +
+ {/* Camera mock elements */} +
+ {/* Corner brackets */} +
+
+
+
+ + {/* Scanning laser line animation */} + + + {/* Mock product inside */} +
🍪
+
+ +

+ Point at any item label +

+
+ + {/* Bottom sheet showing scanning result */} + +
+
+ 🍪 +
+
+
+ + Match Found + + 200m away +
+

Chocolate Chip Cookies

+

Available at Sri Krishna Bakery

+
+
+
+ +
+
+
+ ), + }, + // 2: Rewards + { + id: "rewards", + content: ( +
+ {/* Header */} +
+ Nearle Club + + Gold Tier + +
+ + {/* Points Card */} +
+
+ {/* Decorative background shape */} +
+ + Available Points +

2,450

+ +
+ Next reward at 3,000 pts + 81% +
+
+
+
+
+
+ + {/* Active Offers */} +
+

+ Available Rewards +

+
+ {[ + { + title: "₹50 Off sweets", + store: "Sri Krishna Sweets", + points: "500 pts", + icon: "🍰", + }, + { + title: "Free Organic Honey", + store: "Organic Greens Store", + points: "1200 pts", + icon: "🍯", + }, + { + title: "₹100 Off order", + store: "A1 Biryani House", + points: "900 pts", + icon: "🍗", + }, + ].map((reward, idx) => ( +
+
+ {reward.icon} +
+
{reward.title}
+

{reward.store}

+
+
+ +
+ ))} +
+
+ + {/* Bottom Nav Bar */} +
+
+ + Explore +
+
+ + Favorites +
+
+ + Rewards +
+
+ + Orders +
+
+
+ ), + }, + // 3: Orders (Pickup/Delivery & Reordering) + { + id: "orders", + content: ( +
+ {/* Header */} +
+ Track Order + + Out for Delivery + +
+ + {/* Map simulation */} +
+ {/* Roads */} + + + + + {/* Route */} + + + + {/* Store Pin */} +
+ +
+ + {/* Delivery Biker Pin */} + + + + + {/* Customer Pin */} +
+ +
+
+ + {/* Order Details */} +
+
+
+
+

Sri Krishna Sweets

+

Order #88392 • Delivery in 12 mins

+
+ ₹240 +
+
+
+ 1x Special Mysore Pak (250g) + ₹160 +
+
+ 1x Fine Laddu (4 pcs) + ₹80 +
+
+
+ + {/* Quick Reorder Section */} +
+ + Order Again + +
+
+
Last ordered 3 days ago
+

Mysore Pak from Sri Krishna Sweets

+
+ +
+
+
+ + {/* Bottom Nav Bar */} +
+
+ + Explore +
+
+ + Favorites +
+
+ + Rewards +
+
+ + Orders +
+
+
+ ), + }, + ]; + + return ( +
+ {/* Decorative ambient background glows */} +
+ + {/* Phone chassis */} + + {/* Dynamic Island */} +
+ + +
+ + {/* Gloss overlay reflection */} +
+ + {/* Screens container */} +
+ + + {screens[activeScreen]?.content} + + +
+ + + {/* Small floating decorative location pins and subtle connection dots */} +
+ + 📍 + 300m away + +
+ +
+ + 🎁 + +50 pts + +
+ + {/* Decorative dot connectors */} + + {/* Left connector */} + + + + {/* Right connector */} + + + +
+ ); +} diff --git a/src/components/platform/ProductFeatureGrid.tsx b/src/components/platform/ProductFeatureGrid.tsx index c181667..3e30e7b 100644 --- a/src/components/platform/ProductFeatureGrid.tsx +++ b/src/components/platform/ProductFeatureGrid.tsx @@ -91,11 +91,42 @@ export function ProductFeatureGrid({
-
- {/* ── Animated device illustration (parallax) ── */} +
+ {/* ── Compact 2-Column Feature Grid (Left on Desktop) ── */} + +
+ {features.map((f) => ( + +
+ + + +

+ {f.title} +

+
+

+ {f.desc} +

+
+ ))} +
+
+ + {/* ── Animated device illustration (Right on Desktop) ── */} {/* ambient glow */}
{isPhone ? : } - - {/* ── Editorial feature list (was a 4-col card grid) ── */} - - {/* connection line threading the icons */} -
{footnote && (