tia/src/components/marketing/PhoneMockup.tsx
Mannu 39b2787484 fix(hero): remove floating screen label above phone mockup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 10:39:29 +05:30

322 lines
13 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState, useEffect, useRef, useCallback } from "react";
const SCREENS = [
{ label: "🏡 Home", key: "home" },
{ label: "💉 Vaccinations", key: "vaccines" },
{ label: "📸 Memories", key: "memories" },
] as const;
// ── Screen 0: Home / Quick Log ──────────────────────────────────
function HomeScreen() {
return (
<div className="w-full h-full bg-gradient-to-br from-rose-50 to-amber-50 flex flex-col overflow-hidden text-[10px]">
{/* Status bar */}
<div className="flex items-center justify-between px-4 pt-3 pb-1">
<span className="font-semibold text-gray-600 text-[9px]">9:41</span>
<div className="flex items-center gap-1 text-gray-500 text-[9px]">
<span></span>
<span>WiFi</span>
<span>🔋</span>
</div>
</div>
{/* Top nav */}
<div className="flex items-center justify-between px-3 pb-1">
<div className="w-6 h-5 flex flex-col justify-between py-0.5">
{[0,1,2].map(i => <div key={i} className="h-0.5 w-4 bg-gray-500 rounded" />)}
</div>
<div className="flex items-center gap-2 text-[11px]">
<span></span>
<span className="text-red-500 font-bold text-[10px]">🆘</span>
</div>
</div>
{/* Greeting */}
<div className="px-3 pb-2">
<p className="font-bold text-[13px] text-gray-900">Good morning 👋</p>
<p className="text-gray-500 text-[9px]">How is Arjun doing today?</p>
</div>
{/* Baby card */}
<div className="mx-3 mb-2 bg-white rounded-2xl shadow-sm px-3 py-2 flex items-center gap-3">
<div className="w-10 h-10 bg-rose-100 rounded-full flex items-center justify-center text-lg flex-shrink-0">
👶
</div>
<div className="flex-1">
<p className="font-semibold text-gray-900 text-[11px]">Arjun</p>
<p className="text-gray-500 text-[9px]">4 months</p>
</div>
<span className="text-gray-400 text-[11px]"></span>
</div>
{/* Today summary */}
<div className="mx-3 mb-2 bg-white rounded-2xl shadow-sm">
<div className="grid grid-cols-3 divide-x divide-gray-100">
{[
{ icon: "🍼", label: "Feeds", count: 4, last: "2m ago" },
{ icon: "🚼", label: "Diapers", count: 3, last: "1h ago" },
{ icon: "😴", label: "Sleep", count: 1, last: "3h ago" },
].map(item => (
<div key={item.label} className="flex flex-col items-center py-2 px-1">
<span className="text-sm mb-0.5">{item.icon}</span>
<span className="text-[13px] font-bold text-gray-800 leading-tight">{item.count}</span>
<span className="text-[8px] text-gray-400">{item.label}</span>
<span className="text-[8px] text-rose-400 mt-0.5">{item.last}</span>
</div>
))}
</div>
</div>
{/* Quick Log */}
<div className="px-3 mb-2">
<p className="font-semibold text-gray-800 text-[10px] mb-1.5">Quick Log</p>
<div className="flex gap-2">
{[["🍼","Feed"],["😴","Sleep"],["🚼","Diaper"]].map(([icon, lbl]) => (
<div key={lbl} className="flex flex-col items-center bg-white rounded-xl shadow-sm py-2 px-3 gap-0.5">
<span className="text-lg">{icon}</span>
<span className="text-[9px] text-gray-600">{lbl}</span>
</div>
))}
</div>
</div>
{/* Recent Activity */}
<div className="px-3 flex-1 overflow-hidden">
<div className="flex justify-between items-center mb-1.5">
<p className="font-semibold text-gray-800 text-[10px]">Recent Activity</p>
<span className="text-rose-500 text-[9px]">See all </span>
</div>
<div className="space-y-1.5">
{[
{ icon: "🍼", label: "Feed", detail: "90 ml", time: "10:42 AM" },
{ icon: "😴", label: "Sleep", detail: "2h", time: "8:30 AM" },
{ icon: "🚼", label: "Diaper",detail: "", time: "7:00 AM" },
].map(row => (
<div key={row.time} className="flex items-center justify-between bg-white rounded-xl px-2.5 py-1.5">
<div className="flex items-center gap-2">
<span className="text-sm">{row.icon}</span>
<div>
<p className="font-medium text-gray-800 text-[10px]">{row.label}</p>
<p className="text-gray-400 text-[8px]">{row.time}</p>
</div>
</div>
{row.detail && <span className="text-gray-400 text-[9px]">{row.detail}</span>}
</div>
))}
</div>
</div>
{/* Bottom tab bar strip */}
<div className="mt-auto border-t border-gray-100 bg-white flex justify-around py-1.5 px-2">
{[["🏡","Home"],["📋","Activity"],["✨","AI"],["☰","Menu"]].map(([icon, lbl]) => (
<div key={lbl} className="flex flex-col items-center gap-0.5">
<span className="text-sm">{icon}</span>
<span className={`text-[7px] ${lbl === "Home" ? "text-rose-500 font-semibold" : "text-gray-400"}`}>{lbl}</span>
</div>
))}
</div>
</div>
);
}
// ── Screen 1: Vaccinations ──────────────────────────────────────
function VaccinationsScreen() {
return (
<div className="w-full h-full bg-gradient-to-br from-rose-50 to-amber-50 flex flex-col overflow-hidden text-[10px]">
{/* Header */}
<div className="flex items-center gap-2 px-3 pt-8 pb-3">
<span className="text-gray-500 text-sm"></span>
<p className="font-bold text-gray-900 text-[13px]">Medical</p>
</div>
{/* Tab bar */}
<div className="px-3 mb-2">
<div className="flex gap-1 bg-white rounded-xl p-1 shadow-sm">
{["Vaccines","Medicine","Allergies"].map((t, i) => (
<div key={t} className={`flex-1 text-center py-1 rounded-lg text-[8px] font-medium ${i === 0 ? "bg-rose-500 text-white" : "text-gray-500"}`}>
{t}
</div>
))}
</div>
</div>
<p className="px-3 font-semibold text-gray-800 text-[10px] mb-2">IAP Schedule</p>
{/* Status tabs */}
<div className="px-3 mb-2">
<div className="flex gap-1">
{[["Upcoming (3)","rose"],["Completed (4)","gray"],["Overdue (0)","gray"]].map(([lbl, col]) => (
<div key={lbl} className={`px-2 py-1 rounded-full text-[8px] font-medium border ${col === "rose" ? "bg-rose-100 text-rose-700 border-rose-200" : "bg-white text-gray-500 border-gray-200"}`}>
{lbl}
</div>
))}
</div>
</div>
{/* Vaccine rows */}
<div className="px-3 space-y-1.5 flex-1 overflow-hidden">
{[
{ name: "OPV-1", due: "15 Jul 2025", done: false },
{ name: "Pentavalent-1", due: "15 Jul 2025", done: false },
{ name: "PCV-1", due: "10 Jul 2025", done: true },
{ name: "Rota-1", due: "15 Jul 2025", done: false },
].map(v => (
<div key={v.name} className="bg-white rounded-xl px-2.5 py-2 flex items-center justify-between shadow-sm">
<div>
<p className="font-medium text-gray-900 text-[10px]">{v.name}</p>
<p className="text-gray-400 text-[8px]">Due: {v.due}</p>
</div>
{v.done
? <span className="text-green-500 font-bold text-sm"></span>
: <div className="px-2 py-1 bg-rose-400 text-white rounded-lg text-[8px] font-medium">Mark Given</div>
}
</div>
))}
</div>
{/* Telegram chip */}
<div className="mx-3 mt-2 mb-3 bg-sky-50 border border-sky-200 rounded-xl px-3 py-2 flex items-center gap-2">
<span className="text-sm">📲</span>
<p className="text-sky-700 text-[9px] font-medium">Telegram reminder in 3 days</p>
</div>
{/* Bottom tab strip */}
<div className="border-t border-gray-100 bg-white flex justify-around py-1.5 px-2">
{[["🏡","Home"],["📋","Activity"],["✨","AI"],["☰","Menu"]].map(([icon, lbl]) => (
<div key={lbl} className="flex flex-col items-center gap-0.5">
<span className="text-sm">{icon}</span>
<span className="text-[7px] text-gray-400">{lbl}</span>
</div>
))}
</div>
</div>
);
}
// ── Screen 2: Memories ──────────────────────────────────────────
function MemoriesScreen() {
return (
<div className="w-full h-full bg-gradient-to-br from-rose-50 to-amber-50 flex flex-col overflow-hidden text-[10px]">
{/* Header */}
<div className="flex items-center gap-2 px-3 pt-8 pb-3">
<span className="text-gray-500 text-sm"></span>
<p className="font-bold text-gray-900 text-[13px]">Memories</p>
</div>
{/* Folder tabs */}
<div className="px-3 mb-3">
<div className="flex gap-1.5 overflow-hidden">
{[["🌟","All"],["👣","First Steps"],["🛁","Bath Time"],["🍼","Feeding"]].map(([emoji, lbl], i) => (
<div key={lbl} className={`flex-shrink-0 flex items-center gap-1 px-2 py-1 rounded-full text-[8px] font-medium border ${i === 0 ? "bg-rose-100 text-rose-700 border-rose-200" : "bg-white text-gray-500 border-gray-200"}`}>
<span>{emoji}</span><span>{lbl}</span>
</div>
))}
</div>
</div>
{/* Photo grid */}
<div className="px-3 grid grid-cols-2 gap-2 flex-1 overflow-hidden">
{[
{ bg: "bg-rose-200", emoji: "😊", caption: "First smile" },
{ bg: "bg-amber-200", emoji: "🛁", caption: "Bath time" },
{ bg: "bg-violet-200", emoji: "🏆", caption: "4 months!" },
{ bg: "bg-green-200", emoji: "👨‍👩‍👧", caption: "With Nani" },
].map(photo => (
<div key={photo.caption} className={`${photo.bg} rounded-xl flex flex-col items-center justify-center aspect-square gap-1`}>
<span className="text-2xl">{photo.emoji}</span>
<span className="text-[8px] text-gray-600 font-medium">{photo.caption}</span>
</div>
))}
</div>
{/* Upload row */}
<div className="mx-3 mt-2 mb-2">
<div className="border-2 border-dashed border-rose-200 rounded-xl flex items-center justify-center py-2 gap-2">
<span className="text-sm">📷</span>
<span className="text-rose-400 text-[9px] font-medium">Add memory</span>
</div>
</div>
{/* Bottom tab strip */}
<div className="border-t border-gray-100 bg-white flex justify-around py-1.5 px-2">
{[["🏡","Home"],["📋","Activity"],["✨","AI"],["☰","Menu"]].map(([icon, lbl]) => (
<div key={lbl} className="flex flex-col items-center gap-0.5">
<span className="text-sm">{icon}</span>
<span className="text-[7px] text-gray-400">{lbl}</span>
</div>
))}
</div>
</div>
);
}
// ── Main component ──────────────────────────────────────────────
export function PhoneMockup() {
const [active, setActive] = useState(0);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const start = useCallback(() => {
if (intervalRef.current) clearInterval(intervalRef.current);
intervalRef.current = setInterval(() => {
setActive(prev => (prev + 1) % SCREENS.length);
}, 2500);
}, []);
const stop = useCallback(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, []);
useEffect(() => {
start();
return stop;
}, [start, stop]);
const screenComponents = [<HomeScreen key="home" />, <VaccinationsScreen key="vax" />, <MemoriesScreen key="mem" />];
return (
<div className="flex flex-col items-center gap-3">
{/* Phone */}
<div
className="relative"
style={{ width: 280 }}
onMouseEnter={stop}
onMouseLeave={start}
>
{/* Device shell */}
<div className="absolute inset-0 -m-3 rounded-[42px] bg-gray-900 shadow-2xl" />
{/* Screen */}
<div className="relative rounded-[34px] overflow-hidden bg-white" style={{ height: 580 }}>
{screenComponents.map((screen, i) => (
<div
key={i}
className={`absolute inset-0 transition-opacity duration-500 ${active === i ? "opacity-100" : "opacity-0 pointer-events-none"}`}
>
{screen}
</div>
))}
{/* Dot indicators */}
<div className="absolute bottom-3 left-0 right-0 flex justify-center gap-1.5 z-10">
{SCREENS.map((_, i) => (
<button
key={i}
onClick={() => { stop(); setActive(i); }}
className={`w-2 h-2 rounded-full transition-all duration-300 ${active === i ? "bg-rose-500 w-4" : "bg-rose-200"}`}
aria-label={`Show screen ${i + 1}`}
/>
))}
</div>
</div>
{/* Notch */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-6 bg-gray-900 rounded-b-2xl z-10" />
</div>
</div>
);
}