optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -3,13 +3,15 @@ import ProfileCoverEditor from './ProfileCoverEditor'
import LevelBadge from '../xp/LevelBadge'
import XPProgressBar from '../xp/XPProgressBar'
import FollowButton from '../social/FollowButton'
import FollowersPreview from '../social/FollowersPreview'
import MutualFollowersBadge from '../social/MutualFollowersBadge'
function formatCompactNumber(value) {
const numeric = Number(value ?? 0)
return numeric.toLocaleString()
}
export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing, followerCount, heroBgUrl, countryName, leaderboardRank, extraActions = null }) {
export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing, followerCount, recentFollowers = [], followContext = null, heroBgUrl, countryName, leaderboardRank, extraActions = null }) {
const [following, setFollowing] = useState(viewerIsFollowing)
const [count, setCount] = useState(followerCount)
const [editorOpen, setEditorOpen] = useState(false)
@@ -22,11 +24,10 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
? new Date(user.created_at).toLocaleDateString('en-US', { month: 'long', year: 'numeric' })
: null
const bio = profile?.bio || profile?.about || ''
const heroFacts = [
const progressPercent = Math.round(Number(user?.progress_percent ?? 0))
const heroStats = [
{ label: 'Followers', value: formatCompactNumber(count) },
{ label: 'Level', value: `Lv ${formatCompactNumber(user?.level ?? 1)}` },
{ label: 'Progress', value: `${Math.round(Number(user?.progress_percent ?? 0))}%` },
{ label: 'Member since', value: joinDate ?? 'Recently joined' },
]
return (
@@ -99,7 +100,7 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
</div>
<div className="min-w-0 flex-1 text-center md:text-left">
<div className="grid gap-5 xl:grid-cols-[minmax(0,1fr)_280px] xl:items-start">
<div className="grid gap-5 xl:grid-cols-[minmax(0,1fr)_430px] xl:items-start">
<div className="min-w-0">
<div className="flex flex-wrap items-center justify-center gap-2 md:justify-start">
<span className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300">
@@ -115,6 +116,7 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 md:justify-start">
<LevelBadge level={user?.level} rank={user?.rank} />
{!isOwner ? <MutualFollowersBadge context={followContext} /> : null}
{countryName ? (
<span className="inline-flex items-center gap-1.5 rounded-full border border-white/10 bg-white/5 px-3 py-1.5 text-xs text-slate-300">
{profile?.country_code ? (
@@ -171,7 +173,15 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
</div>
<div className="space-y-3 xl:pt-1">
<div className="flex flex-wrap items-center justify-center gap-2 xl:justify-end">
{!isOwner && recentFollowers?.length > 0 ? (
<FollowersPreview
users={followContext?.follower_overlap?.users?.length ? followContext.follower_overlap.users : recentFollowers}
label={followContext?.follower_overlap?.label || `${formatCompactNumber(followerCount)} followers`}
href={`/@${uname}/activity`}
/>
) : null}
<div className="flex flex-wrap items-center justify-center gap-2 xl:flex-nowrap xl:justify-end">
{extraActions}
{isOwner ? (
<>
@@ -198,8 +208,10 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
username={uname}
initialFollowing={following}
initialCount={count}
className="shrink-0 whitespace-nowrap"
followingClassName="border border-emerald-400/40 bg-emerald-500/12 text-emerald-300 hover:bg-emerald-500/18"
idleClassName="border border-sky-400/40 bg-sky-500/12 text-sky-200 hover:bg-sky-500/20"
sizeClassName="px-3.5 py-2 text-sm"
onChange={({ following: nextFollowing, followersCount }) => {
setFollowing(nextFollowing)
setCount(followersCount)
@@ -216,7 +228,7 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
}
}}
aria-label="Share profile"
className="inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-2.5 text-sm font-medium text-slate-300 transition-all hover:bg-white/[0.08] hover:text-white"
className="inline-flex shrink-0 items-center gap-2 whitespace-nowrap rounded-2xl border border-white/10 bg-white/[0.04] px-3.5 py-2 text-sm font-medium text-slate-300 transition-all hover:bg-white/[0.08] hover:text-white"
>
<i className="fa-solid fa-share-nodes fa-fw" />
Share
@@ -225,16 +237,32 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
)}
</div>
<div className="grid grid-cols-2 gap-2 text-left">
{heroFacts.map((fact) => (
<div
key={fact.label}
className="rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]"
>
<div className="text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500">{fact.label}</div>
<div className="mt-1.5 text-sm font-semibold tracking-tight text-white md:text-base">{fact.value}</div>
</div>
))}
<div className="rounded-[24px] border border-white/10 bg-[linear-gradient(180deg,rgba(15,23,42,0.72),rgba(9,17,31,0.92))] p-3 text-left shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]">
<div className="grid grid-cols-2 gap-2">
{heroStats.map((fact) => (
<div
key={fact.label}
className="rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2.5"
>
<div className="text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500">{fact.label}</div>
<div className="mt-1 text-sm font-semibold tracking-tight text-white md:text-[15px]">{fact.value}</div>
</div>
))}
</div>
<div className="mt-2.5 flex flex-wrap items-center gap-2">
<span className="inline-flex items-center gap-1.5 rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-[11px] font-medium text-slate-300">
<span className="h-1.5 w-1.5 rounded-full bg-cyan-300" />
Progress {progressPercent}%
</span>
{joinDate ? (
<span className="inline-flex items-center gap-1.5 rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-[11px] font-medium text-slate-300">
<i className="fa-solid fa-calendar-days text-[10px] text-slate-500" />
Since {joinDate}
</span>
) : null}
</div>
</div>
</div>
</div>
@@ -246,10 +274,8 @@ export default function ProfileHero({ user, profile, isOwner, viewerIsFollowing,
</div>
<ProfileCoverEditor
open={editorOpen}
isOpen={editorOpen}
onClose={() => setEditorOpen(false)}
currentCoverUrl={coverUrl}
currentPosition={coverPosition}
coverUrl={coverUrl}
coverPosition={coverPosition}
onCoverUpdated={(nextUrl, nextPosition) => {