|
1 | | -import React from "react"; |
2 | | -import { Globe2, Link2 } from "lucide-react"; |
3 | | -import { getAvatarUrl, getConnectedPlatforms, getVisibleLinks, formatCompactNumber } from "./dashboardUtils"; |
| 1 | +import { useMemo } from "react"; |
| 2 | +import { getAvatarUrl, getBannerUrl } from "./dashboardUtils"; |
4 | 3 |
|
5 | | -const MobilePreview = React.memo(function MobilePreview({ |
| 4 | +export default function MobilePreview({ |
6 | 5 | user, |
7 | 6 | links, |
8 | 7 | socialStats, |
| 8 | + analytics |
9 | 9 | }) { |
10 | 10 | const avatarUrl = getAvatarUrl(user); |
11 | | - const visibleLinks = getVisibleLinks(links).slice(0, 5); |
12 | | - const connectedPlatforms = getConnectedPlatforms(user); |
| 11 | + const bannerUrl = getBannerUrl(user); |
13 | 12 |
|
14 | 13 | return ( |
15 | | - <div className="mx-auto w-full max-w-[320px] rounded-[48px] border border-[var(--saas-border)] bg-[#050505] p-2.5 shadow-[0_40px_100px_rgba(0,0,0,0.6)] ring-1 ring-white/10 ring-inset"> |
16 | | - <div className="mx-auto mb-3 h-6 w-28 rounded-full bg-black/80 flex items-center justify-center"> |
17 | | - <div className="w-10 h-1 rounded-full bg-white/10" /> |
18 | | - </div> |
19 | | - |
20 | | - <div className="overflow-hidden rounded-[38px] border border-[var(--saas-border)] bg-gradient-to-b from-[#0e0e11] to-[#050505] p-6 relative"> |
21 | | - {/* Ambient background glow */} |
22 | | - <div className="absolute -top-20 -left-20 w-40 h-40 bg-[var(--saas-accent-primary)] opacity-10 blur-[60px] rounded-full pointer-events-none" /> |
| 14 | + <div className="flex flex-col items-center"> |
| 15 | + {/* Mock Phone Frame */} |
| 16 | + <div className="relative w-[340px] aspect-[9/18.5] bg-[#0b0e14] rounded-[3.5rem] phone-frame overflow-hidden flex flex-col font-['Inter'] ring-1 ring-white/5 shadow-2xl"> |
| 17 | + |
| 18 | + {/* Phone Notch Shadow */} |
| 19 | + <div className="absolute top-0 left-1/2 -translate-x-1/2 w-32 h-6 bg-surface-container-highest rounded-b-2xl z-20"></div> |
23 | 20 |
|
24 | | - <div className="flex flex-col items-center text-center relative z-10"> |
25 | | - <div className="h-22 w-22 p-1 overflow-hidden rounded-[32px] border border-[var(--saas-border)] bg-white/5 shadow-2xl relative group"> |
26 | | - <div className="absolute inset-0 bg-[var(--saas-accent-gradient)] opacity-20 blur-xl group-hover:opacity-40 transition-opacity" /> |
27 | | - {avatarUrl ? ( |
28 | | - <img |
29 | | - src={avatarUrl} |
30 | | - alt={user?.name || user?.username || "Creator avatar"} |
31 | | - className="h-full w-full object-cover rounded-[28px] relative z-10 shadow-lg" |
32 | | - /> |
| 21 | + {/* Screen Content Wrapper */} |
| 22 | + <div className="h-full w-full overflow-y-auto no-scrollbar relative flex flex-col"> |
| 23 | + |
| 24 | + {/* Cover / Banner Section */} |
| 25 | + <div className="h-44 w-full relative shrink-0"> |
| 26 | + {bannerUrl ? ( |
| 27 | + <img src={bannerUrl} className="w-full h-full object-cover" alt="Banner" /> |
33 | 28 | ) : ( |
34 | | - <div className="flex h-full w-full items-center justify-center text-2xl font-black text-white bg-[var(--saas-accent-gradient)] relative z-10 rounded-[28px]"> |
35 | | - {(user?.username || user?.name || "L").charAt(0).toUpperCase()} |
36 | | - </div> |
| 29 | + <div className="w-full h-full bg-surface-container-highest/50" /> |
37 | 30 | )} |
| 31 | + <div className="absolute inset-0 bg-gradient-to-t from-[#0b0e14] via-[#0b0e14]/40 to-transparent" /> |
38 | 32 | </div> |
39 | | - |
40 | | - <div className="mt-5"> |
41 | | - <h4 className="text-xl font-black text-white tracking-tight leading-none"> |
42 | | - @{user?.username || "creator"} |
43 | | - </h4> |
44 | | - <div className="mt-2.5 mx-auto h-0.5 w-6 rounded-full bg-[var(--saas-accent-primary)]" /> |
45 | | - <p className="mt-4 text-[13px] leading-relaxed font-medium text-white/50 px-2 line-clamp-3"> |
46 | | - {user?.bio || "Crafting something extraordinary for the digital world."} |
| 33 | + |
| 34 | + {/* Profile Identity Details */} |
| 35 | + <div className="px-6 -mt-16 relative z-10 flex flex-col items-center text-center"> |
| 36 | + <div className="w-24 h-24 rounded-full p-0.5 bg-gradient-to-tr from-primary via-primary-container to-tertiary shadow-2xl shadow-primary/20"> |
| 37 | + <div className="w-full h-full rounded-full border-4 border-[#0b0e14] overflow-hidden bg-surface-dim"> |
| 38 | + {avatarUrl ? ( |
| 39 | + <img src={avatarUrl} className="w-full h-full object-cover" alt="Avatar" /> |
| 40 | + ) : ( |
| 41 | + <div className="w-full h-full bg-surface-container-high flex items-center justify-center text-primary/40"> |
| 42 | + <span className="material-symbols-outlined text-4xl">person</span> |
| 43 | + </div> |
| 44 | + )} |
| 45 | + </div> |
| 46 | + </div> |
| 47 | + |
| 48 | + <div className="mt-4 space-y-1"> |
| 49 | + <h3 className="text-xl font-black text-white tracking-tight uppercase"> |
| 50 | + {user?.full_name || "Julian Marcus"} |
| 51 | + </h3> |
| 52 | + <p className="text-sm font-bold text-primary tracking-widest uppercase opacity-80"> |
| 53 | + @{user?.username || "creator_hub"} |
| 54 | + </p> |
| 55 | + </div> |
| 56 | + |
| 57 | + <p className="mt-4 text-[11px] leading-relaxed text-on-surface-variant font-medium px-4"> |
| 58 | + {user?.bio || "Digital nomad & minimalist designer. Sharing my journey through pixels and code."} |
47 | 59 | </p> |
48 | 60 | </div> |
49 | | - </div> |
50 | | - |
51 | | - <div className="mt-8 flex flex-wrap justify-center gap-2 relative z-10"> |
52 | | - {connectedPlatforms.length ? ( |
53 | | - connectedPlatforms.slice(0, 4).map((platform) => { |
54 | | - const Icon = platform.icon; |
55 | | - const stat = socialStats?.[platform.socialKey]; |
56 | | - const count = |
57 | | - stat?.followers ?? |
58 | | - stat?.subscriberCount ?? |
59 | | - stat?.subscribers ?? |
60 | | - stat?.memberCount ?? |
61 | | - stat?.members; |
62 | 61 |
|
63 | | - return ( |
64 | | - <div |
65 | | - key={platform.key} |
66 | | - className="flex items-center gap-2 rounded-2xl border border-white/5 bg-white/5 px-4 py-2 text-white/90 backdrop-blur-sm transition-all hover:bg-white/10" |
| 62 | + {/* Dynamic Link Matrices */} |
| 63 | + <div className="mt-10 px-6 space-y-4 pb-20 w-full"> |
| 64 | + {links && links.length > 0 ? ( |
| 65 | + links.map((link) => ( |
| 66 | + <div |
| 67 | + key={link.id} |
| 68 | + className="w-full py-4.5 px-6 glass-panel border border-white/5 rounded-2xl flex items-center justify-between group cursor-pointer transition-all hover:bg-white/5 active:scale-[0.98]" |
67 | 69 | > |
68 | | - <Icon className="h-3.5 w-3.5" style={{ color: platform.color }} /> |
69 | | - <span className="text-[10px] font-black uppercase tracking-wider"> |
70 | | - {count ? formatCompactNumber(count) : "Live"} |
71 | | - </span> |
72 | | - </div> |
73 | | - ); |
74 | | - }) |
75 | | - ) : ( |
76 | | - <div className="h-8 w-24 rounded-full bg-white/5 animate-pulse" /> |
77 | | - )} |
78 | | - </div> |
79 | | - |
80 | | - <div className="mt-8 space-y-3 relative z-10"> |
81 | | - {visibleLinks.length ? ( |
82 | | - visibleLinks.map((link) => ( |
83 | | - <div |
84 | | - key={link.id} |
85 | | - className="group flex items-center justify-between rounded-2xl border border-white/5 bg-white/5 px-4 py-4 transition-all hover:bg-white/10 hover:border-white/10 hover:-translate-y-0.5 shadow-sm" |
86 | | - > |
87 | | - <div className="min-w-0"> |
88 | | - <p className="truncate text-sm font-bold text-white tracking-tight"> |
89 | | - {link.title} |
90 | | - </p> |
91 | | - <p className="mt-1 truncate text-[10px] font-bold text-white/30 uppercase tracking-widest font-mono"> |
92 | | - {link.url.replace(/^https?:\/\/(www\.)?/, '')} |
93 | | - </p> |
94 | | - </div> |
95 | | - <div className="h-9 w-9 shrink-0 flex items-center justify-center rounded-xl bg-white/5 text-white/40 group-hover:bg-[var(--saas-accent-primary)] group-hover:text-black transition-all"> |
96 | | - <Link2 className="h-4 w-4" /> |
| 70 | + <div className="flex items-center gap-4"> |
| 71 | + <div className="w-10 h-10 rounded-xl bg-surface-container-highest flex items-center justify-center text-primary shadow-inner"> |
| 72 | + <span className="material-symbols-outlined text-xl"> |
| 73 | + {link.platform === "General" ? "rocket_launch" : "alternate_email"} |
| 74 | + </span> |
| 75 | + </div> |
| 76 | + <span className="text-sm font-bold text-white tracking-wide uppercase">{link.title}</span> |
| 77 | + </div> |
| 78 | + <span className="material-symbols-outlined text-on-surface-variant text-[16px] opacity-40">chevron_right</span> |
97 | 79 | </div> |
| 80 | + )) |
| 81 | + ) : ( |
| 82 | + <div className="space-y-4"> |
| 83 | + {[1, 2, 3].map(i => ( |
| 84 | + <div key={i} className="w-full h-16 bg-white/5 rounded-2xl border border-white/5 opacity-40 animate-pulse" /> |
| 85 | + ))} |
98 | 86 | </div> |
99 | | - )) |
100 | | - ) : ( |
101 | | - [1, 2, 3].map(i => ( |
102 | | - <div key={i} className="h-16 w-full rounded-2xl bg-white/5 animate-pulse" /> |
103 | | - )) |
104 | | - )} |
105 | | - </div> |
| 87 | + )} |
| 88 | + </div> |
106 | 89 |
|
107 | | - <div className="mt-8 flex items-center justify-center gap-2.5 py-4 border-t border-white/5"> |
108 | | - <Globe2 className="h-3.5 w-3.5 text-white/20" /> |
109 | | - <span className="text-[10px] font-black uppercase tracking-[0.2em] text-white/40"> |
110 | | - linkhub.to/{user?.username || "identity"} |
111 | | - </span> |
| 90 | + {/* Social Logo Watermark */} |
| 91 | + <div className="mt-auto py-8 flex justify-center opacity-10"> |
| 92 | + <span className="text-[10px] font-black tracking-[0.5em] text-white">LINKHUB</span> |
| 93 | + </div> |
112 | 94 | </div> |
| 95 | + |
| 96 | + {/* Home Interaction Bar */} |
| 97 | + <div className="absolute bottom-1.5 left-1/2 -translate-x-1/2 w-32 h-1 bg-white/20 rounded-full z-20"></div> |
113 | 98 | </div> |
114 | 99 | </div> |
115 | 100 | ); |
116 | | -}); |
117 | | - |
118 | | -export default MobilePreview; |
| 101 | +} |
0 commit comments