2026-02-14 15:26:42 +01:00
|
|
|
'use client'
|
|
|
|
|
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
import { ResponsivePie } from '@nivo/pie'
|
|
|
|
|
import { ResponsiveBar } from '@nivo/bar'
|
2026-02-14 15:26:42 +01:00
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
|
|
import { Badge } from '@/components/ui/badge'
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
import { nivoTheme, BRAND_COLORS } from './chart-theme'
|
2026-02-14 15:26:42 +01:00
|
|
|
|
|
|
|
|
interface DiversityData {
|
|
|
|
|
total: number
|
|
|
|
|
byCountry: { country: string; count: number; percentage: number }[]
|
|
|
|
|
byCategory: { category: string; count: number; percentage: number }[]
|
|
|
|
|
byOceanIssue: { issue: string; count: number; percentage: number }[]
|
|
|
|
|
byTag: { tag: string; count: number; percentage: number }[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface DiversityMetricsProps {
|
|
|
|
|
data: DiversityData
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Convert ISO 3166-1 alpha-2 code to full country name using Intl API */
|
|
|
|
|
function getCountryName(code: string): string {
|
|
|
|
|
if (code === 'Others') return 'Others'
|
|
|
|
|
try {
|
|
|
|
|
const displayNames = new Intl.DisplayNames(['en'], { type: 'region' })
|
|
|
|
|
return displayNames.of(code.toUpperCase()) || code
|
|
|
|
|
} catch {
|
|
|
|
|
return code
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Convert SCREAMING_SNAKE_CASE to Title Case */
|
|
|
|
|
function formatLabel(value: string): string {
|
|
|
|
|
if (!value) return value
|
|
|
|
|
return value
|
|
|
|
|
.replace(/_/g, ' ')
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace(/\b\w/g, (c) => c.toUpperCase())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function DiversityMetricsChart({ data }: DiversityMetricsProps) {
|
2026-02-20 13:42:31 +01:00
|
|
|
if (!data || data.total === 0) {
|
2026-02-14 15:26:42 +01:00
|
|
|
return (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardContent className="flex items-center justify-center py-12">
|
|
|
|
|
<p className="text-muted-foreground">No project data available</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Top countries for pie chart (max 10, others grouped)
|
2026-02-20 13:42:31 +01:00
|
|
|
const topCountries = (data.byCountry || []).slice(0, 10)
|
|
|
|
|
const otherCountries = (data.byCountry || []).slice(10)
|
2026-02-14 15:26:42 +01:00
|
|
|
const countryPieData = otherCountries.length > 0
|
|
|
|
|
? [...topCountries, {
|
|
|
|
|
country: 'Others',
|
|
|
|
|
count: otherCountries.reduce((sum, c) => sum + c.count, 0),
|
|
|
|
|
percentage: otherCountries.reduce((sum, c) => sum + c.percentage, 0),
|
|
|
|
|
}]
|
|
|
|
|
: topCountries
|
|
|
|
|
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
const nivoPieData = countryPieData.map((c) => ({
|
2026-02-20 18:39:53 +01:00
|
|
|
id: c.country === 'Others' ? 'Others' : c.country.toUpperCase(),
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
label: getCountryName(c.country),
|
|
|
|
|
value: c.count,
|
|
|
|
|
}))
|
|
|
|
|
|
2026-02-14 15:26:42 +01:00
|
|
|
// Pre-format category and ocean issue data for display
|
2026-02-20 13:42:31 +01:00
|
|
|
const formattedCategories = (data.byCategory || []).slice(0, 10).map((c) => ({
|
2026-02-14 15:26:42 +01:00
|
|
|
category: formatLabel(c.category),
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
count: c.count,
|
2026-02-14 15:26:42 +01:00
|
|
|
}))
|
|
|
|
|
|
2026-02-20 13:42:31 +01:00
|
|
|
const formattedOceanIssues = (data.byOceanIssue || []).slice(0, 15).map((o) => ({
|
2026-02-14 15:26:42 +01:00
|
|
|
issue: formatLabel(o.issue),
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
count: o.count,
|
2026-02-14 15:26:42 +01:00
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
{/* Summary */}
|
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
|
|
|
<Card>
|
|
|
|
|
<CardContent className="pt-6">
|
|
|
|
|
<div className="text-2xl font-bold">{data.total}</div>
|
|
|
|
|
<p className="text-sm text-muted-foreground">Total Projects</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
<Card>
|
|
|
|
|
<CardContent className="pt-6">
|
2026-02-20 13:42:31 +01:00
|
|
|
<div className="text-2xl font-bold">{(data.byCountry || []).length}</div>
|
2026-02-14 15:26:42 +01:00
|
|
|
<p className="text-sm text-muted-foreground">Countries Represented</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
<Card>
|
|
|
|
|
<CardContent className="pt-6">
|
2026-02-20 13:42:31 +01:00
|
|
|
<div className="text-2xl font-bold">{(data.byCategory || []).length}</div>
|
2026-02-14 15:26:42 +01:00
|
|
|
<p className="text-sm text-muted-foreground">Categories</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
<Card>
|
|
|
|
|
<CardContent className="pt-6">
|
2026-02-20 13:42:31 +01:00
|
|
|
<div className="text-2xl font-bold">{(data.byTag || []).length}</div>
|
2026-02-14 15:26:42 +01:00
|
|
|
<p className="text-sm text-muted-foreground">Unique Tags</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid gap-6 lg:grid-cols-2">
|
|
|
|
|
{/* Country Distribution */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Geographic Distribution</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
<div style={{ height: '400px' }}>
|
2026-02-20 14:09:43 +01:00
|
|
|
{nivoPieData.length > 0 ? <ResponsivePie
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
data={nivoPieData}
|
|
|
|
|
theme={nivoTheme}
|
|
|
|
|
colors={[...BRAND_COLORS]}
|
|
|
|
|
innerRadius={0.4}
|
|
|
|
|
padAngle={0.5}
|
|
|
|
|
cornerRadius={3}
|
|
|
|
|
activeOuterRadiusOffset={8}
|
|
|
|
|
margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
|
|
|
|
|
enableArcLinkLabels={true}
|
|
|
|
|
arcLinkLabelsSkipAngle={10}
|
|
|
|
|
arcLinkLabelsTextColor="#374151"
|
|
|
|
|
arcLinkLabelsThickness={2}
|
|
|
|
|
arcLinkLabelsColor={{ from: 'color' }}
|
|
|
|
|
enableArcLabels={true}
|
|
|
|
|
arcLabelsSkipAngle={10}
|
|
|
|
|
arcLabelsTextColor={{ from: 'color', modifiers: [['darker', 2]] }}
|
|
|
|
|
legends={[
|
|
|
|
|
{
|
|
|
|
|
anchor: 'bottom',
|
|
|
|
|
direction: 'row',
|
|
|
|
|
justify: false,
|
|
|
|
|
translateX: 0,
|
|
|
|
|
translateY: 56,
|
|
|
|
|
itemsSpacing: 0,
|
|
|
|
|
itemWidth: 100,
|
|
|
|
|
itemHeight: 18,
|
|
|
|
|
itemTextColor: '#374151',
|
|
|
|
|
itemDirection: 'left-to-right',
|
|
|
|
|
itemOpacity: 1,
|
|
|
|
|
symbolSize: 12,
|
|
|
|
|
symbolShape: 'circle',
|
|
|
|
|
},
|
|
|
|
|
]}
|
2026-02-20 14:09:43 +01:00
|
|
|
/> : (
|
|
|
|
|
<p className="text-muted-foreground text-center py-8">No geographic data</p>
|
|
|
|
|
)}
|
2026-02-14 15:26:42 +01:00
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* Category Distribution */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Competition Categories</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
{formattedCategories.length > 0 ? (
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
<div style={{ height: '400px' }}>
|
|
|
|
|
<ResponsiveBar
|
|
|
|
|
data={formattedCategories}
|
|
|
|
|
theme={nivoTheme}
|
|
|
|
|
keys={['count']}
|
|
|
|
|
indexBy="category"
|
|
|
|
|
layout="horizontal"
|
|
|
|
|
colors={[BRAND_COLORS[0]]}
|
|
|
|
|
borderRadius={4}
|
|
|
|
|
margin={{ top: 10, right: 30, bottom: 10, left: 120 }}
|
|
|
|
|
padding={0.3}
|
|
|
|
|
enableLabel={true}
|
|
|
|
|
labelTextColor="#ffffff"
|
|
|
|
|
enableGridX={true}
|
|
|
|
|
enableGridY={false}
|
|
|
|
|
axisBottom={null}
|
|
|
|
|
axisLeft={{
|
|
|
|
|
tickSize: 0,
|
|
|
|
|
tickPadding: 8,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2026-02-14 15:26:42 +01:00
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<p className="text-muted-foreground text-center py-8">No category data</p>
|
|
|
|
|
)}
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Ocean Issues */}
|
|
|
|
|
{formattedOceanIssues.length > 0 && (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Ocean Issues Addressed</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering,
unscored projects, criteria scores, activeRoundCount scoping, email
privacy leaks in juror consistency + workload)
Phase 2-3: Migrate all 9 chart components from Recharts to Nivo
(@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand
theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot
outlier coloring and pie chart label visibility bugs.
Phase 4: Add round-type-aware stats (getRoundTypeStats backend +
RoundTypeStatsCards component) showing appropriate metrics per round
type (intake/filtering/evaluation/submission/mentoring/live/deliberation).
Phase 5: UX improvements — Stage→Round terminology, clickable dashboard
round links, URL-based round selection (?round=), round type indicators
in selectors, accessible Toggle-based cross-round comparison, sortable
project table columns (title/score/evaluations), brand score colors on
dashboard bar chart with aria labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 21:44:38 +01:00
|
|
|
<div style={{ height: '400px' }}>
|
|
|
|
|
<ResponsiveBar
|
|
|
|
|
data={formattedOceanIssues}
|
|
|
|
|
theme={nivoTheme}
|
|
|
|
|
keys={['count']}
|
|
|
|
|
indexBy="issue"
|
|
|
|
|
layout="vertical"
|
|
|
|
|
colors={[BRAND_COLORS[2]]}
|
|
|
|
|
borderRadius={4}
|
|
|
|
|
margin={{ top: 20, right: 30, bottom: 80, left: 40 }}
|
|
|
|
|
padding={0.3}
|
|
|
|
|
enableLabel={true}
|
|
|
|
|
labelTextColor="#ffffff"
|
|
|
|
|
enableGridX={false}
|
|
|
|
|
enableGridY={true}
|
|
|
|
|
axisBottom={{
|
|
|
|
|
tickSize: 0,
|
|
|
|
|
tickPadding: 8,
|
|
|
|
|
tickRotation: -35,
|
|
|
|
|
}}
|
|
|
|
|
axisLeft={{
|
|
|
|
|
tickSize: 0,
|
|
|
|
|
tickPadding: 8,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2026-02-14 15:26:42 +01:00
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Tags Cloud */}
|
2026-02-20 13:42:31 +01:00
|
|
|
{(data.byTag || []).length > 0 && (
|
2026-02-14 15:26:42 +01:00
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Project Tags</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="flex flex-wrap gap-2">
|
2026-02-20 13:42:31 +01:00
|
|
|
{(data.byTag || []).slice(0, 30).map((tag) => (
|
2026-02-14 15:26:42 +01:00
|
|
|
<Badge
|
|
|
|
|
key={tag.tag}
|
|
|
|
|
variant="secondary"
|
|
|
|
|
className="text-sm"
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: `${Math.max(0.75, Math.min(1.4, 0.75 + tag.percentage / 20))}rem`,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{tag.tag} ({tag.count})
|
|
|
|
|
</Badge>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|