Skip to content

Commit 9b4e9dd

Browse files
committed
Improve emoji design for stats
1 parent e714c52 commit 9b4e9dd

1 file changed

Lines changed: 80 additions & 47 deletions

File tree

web/pages/stats.tsx

Lines changed: 80 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1+
import {
2+
ArrowTrendingUpIcon,
3+
BoltIcon,
4+
BuildingLibraryIcon,
5+
ChatBubbleLeftRightIcon,
6+
ChatBubbleOvalLeftIcon,
7+
CheckCircleIcon,
8+
ClipboardDocumentListIcon,
9+
EnvelopeIcon,
10+
HandRaisedIcon,
11+
PuzzlePieceIcon,
12+
QuestionMarkCircleIcon,
13+
ScaleIcon,
14+
StarIcon,
15+
UserIcon,
16+
UsersIcon,
17+
} from '@heroicons/react/24/outline'
118
import clsx from 'clsx'
219
import {type Stats} from 'common/stats'
3-
import {ReactNode, useEffect, useState} from 'react'
20+
import {ComponentType, ReactNode, SVGProps, useEffect, useState} from 'react'
421
import {PageBase} from 'web/components/page-base'
522
import {SEO} from 'web/components/SEO'
623
import ChartMembers from 'web/components/widgets/charts'
@@ -10,16 +27,18 @@ import {getCount} from 'web/lib/supabase/users'
1027

1128
// ─── Types ────────────────────────────────────────────────────────────────────
1229

30+
type IconType = ComponentType<SVGProps<SVGSVGElement>>
31+
1332
interface StatCardProps {
1433
value: string | number | null | undefined
1534
label: string
16-
icon: string
35+
icon: IconType
1736
accent?: 'amber' | 'sage' | 'muted'
1837
large?: boolean
1938
}
2039

2140
interface StatGroupProps {
22-
icon: string
41+
icon: IconType
2342
title: string
2443
children: ReactNode
2544
}
@@ -34,7 +53,7 @@ function formatNumber(n: number): string {
3453

3554
// ─── Stat Card ────────────────────────────────────────────────────────────────
3655

37-
function StatCard({value, label, icon, accent = 'amber', large}: StatCardProps) {
56+
function StatCard({value, label, icon: Icon, accent = 'amber', large}: StatCardProps) {
3857
if (value === null || value === undefined || value === 0) return null
3958

4059
const formatted = typeof value === 'number' ? formatNumber(value) : value
@@ -56,8 +75,8 @@ function StatCard({value, label, icon, accent = 'amber', large}: StatCardProps)
5675
"
5776
>
5877
<div className="flex items-start justify-between mb-3">
59-
<div className="w-9 h-9 rounded-lg bg-canvas-200 border border-canvas-300 flex items-center justify-center text-base flex-shrink-0">
60-
{icon}
78+
<div className="w-9 h-9 rounded-lg bg-primary-100 border border-primary-200 flex items-center justify-center flex-shrink-0">
79+
<Icon className="w-[18px] h-[18px] text-primary-600" strokeWidth={1.8} />
6180
</div>
6281
</div>
6382

@@ -80,11 +99,11 @@ function StatCard({value, label, icon, accent = 'amber', large}: StatCardProps)
8099

81100
// ─── Stat Group ───────────────────────────────────────────────────────────────
82101

83-
function StatGroup({icon, title, children}: StatGroupProps) {
102+
function StatGroup({icon: Icon, title, children}: StatGroupProps) {
84103
return (
85104
<div className="mb-10">
86105
<div className="flex items-center gap-3 mb-4">
87-
<span className="text-base">{icon}</span>
106+
<Icon className="w-4 h-4 text-primary-500" strokeWidth={1.8} />
88107
<span className="text-[11px] font-bold tracking-[1.2px] uppercase text-ink-500">
89108
{title}
90109
</span>
@@ -107,8 +126,8 @@ function ChartCard() {
107126
"
108127
>
109128
<div className="flex items-center gap-2 mb-1">
110-
<div className="w-8 h-8 rounded-lg bg-canvas-200 border border-canvas-300 flex items-center justify-center text-sm">
111-
📈
129+
<div className="w-8 h-8 rounded-lg bg-primary-100 border border-primary-200 flex items-center justify-center">
130+
<ArrowTrendingUpIcon className="w-4 h-4 text-primary-600" strokeWidth={1.8} />
112131
</div>
113132
<div>
114133
<h2 className="text-sm font-bold text-ink-900 leading-tight">
@@ -136,23 +155,28 @@ function HighlightRow({
136155
messages: number | null | undefined
137156
}) {
138157
const t = useT()
139-
const items = [
158+
const items: {
159+
value: number | null | undefined
160+
label: string
161+
icon: IconType
162+
accent: 'amber' | 'sage'
163+
}[] = [
140164
{
141165
value: members,
142166
label: t('stats.highlight.members', 'Total Members'),
143-
icon: '👥',
167+
icon: UsersIcon,
144168
accent: 'amber' as const,
145169
},
146170
{
147171
value: active,
148172
label: t('stats.highlight.active', 'Active (last month)'),
149-
icon: '⚡',
173+
icon: BoltIcon,
150174
accent: 'sage' as const,
151175
},
152176
{
153177
value: messages,
154178
label: t('stats.highlight.messages', 'Messages sent'),
155-
icon: '✉️',
179+
icon: EnvelopeIcon,
156180
accent: 'amber' as const,
157181
},
158182
].filter((i) => !!i.value)
@@ -161,31 +185,34 @@ function HighlightRow({
161185

162186
return (
163187
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-10">
164-
{items.map((item) => (
165-
<div
166-
key={item.label}
167-
className="
188+
{items.map((item) => {
189+
const Icon = item.icon
190+
return (
191+
<div
192+
key={item.label}
193+
className="
168194
relative overflow-hidden
169195
bg-canvas-950 rounded-2xl p-6
170196
border-[1.5px] border-canvas-900
171197
"
172-
>
173-
<div className="w-9 h-9 rounded-lg bg-canvas-900 flex items-center justify-center text-base mb-4">
174-
{item.icon}
175-
</div>
176-
<div
177-
className={clsx(
178-
'text-4xl font-black tracking-tight leading-none mb-2',
179-
item.accent === 'sage' ? 'text-green-500' : 'text-primary-400',
180-
)}
181198
>
182-
{typeof item.value === 'number' ? formatNumber(item.value) : item.value}
199+
<div className="w-9 h-9 rounded-lg bg-canvas-900 flex items-center justify-center mb-4">
200+
<Icon className="w-[18px] h-[18px] text-primary-400" strokeWidth={1.8} />
201+
</div>
202+
<div
203+
className={clsx(
204+
'text-4xl font-black tracking-tight leading-none mb-2',
205+
item.accent === 'sage' ? 'text-green-500' : 'text-primary-400',
206+
)}
207+
>
208+
{typeof item.value === 'number' ? formatNumber(item.value) : item.value}
209+
</div>
210+
<p className="text-xs font-semibold text-white/60 uppercase tracking-wide">
211+
{item.label}
212+
</p>
183213
</div>
184-
<p className="text-xs font-semibold text-white/60 uppercase tracking-wide">
185-
{item.label}
186-
</p>
187-
</div>
188-
))}
214+
)
215+
})}
189216
</div>
190217
)
191218
}
@@ -294,77 +321,83 @@ export default function Stats() {
294321
<ChartCard />
295322

296323
{/* ── Community ── */}
297-
<StatGroup icon="👥" title={t('stats.group.community', 'Community')}>
324+
<StatGroup icon={UsersIcon} title={t('stats.group.community', 'Community')}>
298325
<StatCard
299326
value={data.profiles}
300327
label={t('stats.members', 'Members')}
301-
icon="👤"
328+
icon={UserIcon}
302329
accent="amber"
303330
/>
304331
<StatCard
305332
value={data.active_members}
306333
label={t('stats.active_members', 'Active (last month)')}
307-
icon="⚡"
334+
icon={BoltIcon}
308335
accent="sage"
309336
/>
310337
<StatCard
311338
value={genderRatioLabel}
312339
label={t('stats.gender_ratio', 'Male / Female')}
313-
icon="⚖️"
340+
icon={ScaleIcon}
314341
accent="muted"
315342
/>
316343
<StatCard
317344
value={data.profile_comments}
318345
label={t('stats.endorsements', 'Endorsements')}
319-
icon="⭐"
346+
icon={StarIcon}
320347
accent="amber"
321348
/>
322349
</StatGroup>
323350

324351
{/* ── Conversations ── */}
325-
<StatGroup icon="💬" title={t('stats.group.conversations', 'Conversations')}>
352+
<StatGroup
353+
icon={ChatBubbleLeftRightIcon}
354+
title={t('stats.group.conversations', 'Conversations')}
355+
>
326356
<StatCard
327357
value={data.private_user_message_channels}
328358
label={t('stats.discussions', 'Discussions')}
329-
icon="🗨️"
359+
icon={ChatBubbleOvalLeftIcon}
330360
accent="amber"
331361
/>
332362
<StatCard
333363
value={statsData?.messages}
334364
label={t('stats.messages', 'Messages')}
335-
icon="✉️"
365+
icon={EnvelopeIcon}
336366
accent="sage"
337367
/>
338368
</StatGroup>
339369

340370
{/* ── Compatibility ── */}
341-
<StatGroup icon="🎯" title={t('stats.group.compatibility', 'Compatibility')}>
371+
<StatGroup
372+
icon={PuzzlePieceIcon}
373+
title={t('stats.group.compatibility', 'Compatibility')}
374+
>
342375
<StatCard
343376
value={data.compatibility_prompts}
344377
label={t('stats.compatibility_prompts', 'Prompts Created')}
345-
icon="❓"
378+
icon={QuestionMarkCircleIcon}
346379
accent="amber"
347380
/>
348381
<StatCard
349382
value={data.compatibility_answers}
350383
label={t('stats.prompts_answered', 'Prompts Answered')}
351-
icon="✅"
384+
icon={CheckCircleIcon}
352385
accent="sage"
353386
/>
354387
</StatGroup>
355388

356389
{/* ── Democracy ── */}
357-
<StatGroup icon="🗳️" title={t('stats.group.democracy', 'Democracy')}>
390+
<StatGroup icon={BuildingLibraryIcon} title={t('stats.group.democracy', 'Democracy')}>
358391
<StatCard
359392
value={data.votes}
360393
label={t('stats.proposals', 'Proposals')}
361-
icon="📋"
394+
icon={ClipboardDocumentListIcon}
362395
accent="amber"
363396
/>
364397
<StatCard
365398
value={data.vote_results}
366399
label={t('stats.votes', 'Votes Cast')}
367-
icon="🗳️"
400+
icon={HandRaisedIcon}
368401
accent="sage"
369402
/>
370403
{/*<StatCard*/}

0 commit comments

Comments
 (0)