1- ' use client' ;
1+ " use client" ;
22
3- import {
4- Card , CardHeader , Input , Pagination ,
5- } from "@nextui-org/react" ;
3+ import { Card , CardHeader , Input , Pagination } from "@nextui-org/react" ;
64import { Search , Warehouse , Database , Users , Code2 , Zap } from "lucide-react" ;
75import { useState , useMemo , useEffect } from "react" ;
86import { motion , AnimatePresence } from "framer-motion" ;
@@ -13,7 +11,11 @@ import { EcosystemTypeFilter } from "$/ecosystem-type-filter";
1311import type { EcoRankRecord } from "~/api/typing" ;
1412import MetricCard , { type MetricCardProps } from "$/controls/metric-card" ;
1513import TableHeader from "$/controls/table-header" ;
16- import { staggerContainer , staggerItemScale , fadeInUp } from "@/utils/animations" ;
14+ import {
15+ staggerContainer ,
16+ staggerItemScale ,
17+ fadeInUp ,
18+ } from "@/utils/animations" ;
1719
1820interface EcosystemsPageProps {
1921 ecosystems : EcoRankRecord [ ] ;
@@ -43,7 +45,8 @@ function resolveMetrics(dataSource: {
4345 value : Number ( dataSource . totalDevelopers ) . toLocaleString ( ) ,
4446 icon : < Users size = { 20 } className = "text-primary" /> ,
4547 iconBgClassName : "bg-primary/10" ,
46- tooltip : "Developers with activity (star not included) in this ecosystem (all time)" ,
48+ tooltip :
49+ "Developers with activity (star not included) in this ecosystem (all time)" ,
4750 } ,
4851 {
4952 label : "Ecosystems" ,
@@ -75,25 +78,39 @@ export default function EcosystemsPageClient({
7578
7679 // Filtering state
7780 const [ filterValue , setFilterValue ] = useState ( "" ) ;
78- const [ selectedType , setSelectedType ] = useState < EcosystemType > ( EcosystemType . PUBLIC_CHAIN ) ;
81+ const [ selectedType , setSelectedType ] = useState < EcosystemType > (
82+ EcosystemType . PUBLIC_CHAIN ,
83+ ) ;
7984
8085 // Reset page when ecosystem type changes
8186 useEffect ( ( ) => {
8287 setPage ( 1 ) ;
8388 } , [ selectedType ] ) ;
8489
90+ // First, create a map of ecosystem names to their global ranks (based on actors_core_total)
91+ const ecosystemRanks = useMemo ( ( ) => {
92+ const sorted = [ ...ecosystems ] . sort ( ( a , b ) => {
93+ return Number ( b . actors_core_total ) - Number ( a . actors_core_total ) ;
94+ } ) ;
95+ const rankMap = new Map < string , number > ( ) ;
96+ sorted . forEach ( ( eco , index ) => {
97+ rankMap . set ( eco . eco_name , index + 1 ) ;
98+ } ) ;
99+ return rankMap ;
100+ } , [ ecosystems ] ) ;
101+
85102 // Filter ecosystems based on search query and type
86103 const filteredItems = useMemo ( ( ) => {
87104 let filtered = [ ...ecosystems ] ;
88105
89106 if ( filterValue ) {
90- filtered = filtered . filter ( ecosystem =>
107+ filtered = filtered . filter ( ( ecosystem ) =>
91108 ecosystem . eco_name . toLowerCase ( ) . includes ( filterValue . toLowerCase ( ) ) ,
92109 ) ;
93110 }
94111
95112 // Filter by ecosystem type using the kind field
96- filtered = filtered . filter ( ecosystem =>
113+ filtered = filtered . filter ( ( ecosystem ) =>
97114 getFilterForType ( selectedType , ecosystem . kind ) ,
98115 ) ;
99116
@@ -129,10 +146,12 @@ export default function EcosystemsPageClient({
129146 < div className = "p-2 rounded-lg bg-primary/10" >
130147 < Warehouse size = { 20 } className = "text-primary" />
131148 </ div >
132- < h1 className = "text-3xl font-bold text-gray-900 dark:text-white" > All Ecosystems</ h1 >
149+ < h1 className = "text-3xl font-bold text-gray-900 dark:text-white" >
150+ All Ecosystems
151+ </ h1 >
133152 </ div >
134153 < p className = "text-lg text-gray-600 dark:text-gray-300 max-w-3xl" >
135- Compare metrics across all blockchain and Web3 ecosystems
154+ Compare metrics across all blockchain and Web3 ecosystems
136155 </ p >
137156 </ motion . div >
138157
@@ -143,7 +162,12 @@ export default function EcosystemsPageClient({
143162 animate = "visible"
144163 className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 mb-10"
145164 >
146- { resolveMetrics ( { totalCoreDevelopers, totalDevelopers, totalEcosystems, totalRepositories } ) . map ( ( metric ) => (
165+ { resolveMetrics ( {
166+ totalCoreDevelopers,
167+ totalDevelopers,
168+ totalEcosystems,
169+ totalRepositories,
170+ } ) . map ( ( metric ) => (
147171 < motion . div
148172 key = { metric . label . replaceAll ( " " , "" ) }
149173 variants = { staggerItemScale }
@@ -179,26 +203,51 @@ export default function EcosystemsPageClient({
179203 < div className = "p-2 rounded-lg bg-primary/10" >
180204 < Warehouse size = { 18 } className = "text-primary" />
181205 </ div >
182- < h3 className = "text-lg font-medium text-gray-900 dark:text-white" > Ecosystem Analytics</ h3 >
206+ < h3 className = "text-lg font-medium text-gray-900 dark:text-white" >
207+ Ecosystem Analytics
208+ </ h3 >
183209 </ div >
184210 </ CardHeader >
185211
186212 < div className = "overflow-x-auto" >
187213 < table className = "w-full" >
188214 < thead >
189215 < tr className = "border-t border-border dark:border-border-dark bg-surface dark:bg-surface-dark" >
190- < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-500 uppercase tracking-wider w-12" > #</ th >
216+ < th className = "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-500 uppercase tracking-wider w-12" >
217+ #
218+ </ th >
191219 < TableHeader > Ecosystem</ TableHeader >
192- < TableHeader align = "right" tooltip = "Developers with pull requests and push events in the past year" > Devs</ TableHeader >
193- < TableHeader align = "right" tooltip = "Developers with activity (star not included) in this ecosystem (all time)" > Contributors</ TableHeader >
194- < TableHeader align = "right" tooltip = "Developers with first activity in past 90 days" > New</ TableHeader >
195- < TableHeader align = "right" tooltip = "Total repositories in this ecosystem" > Repos</ TableHeader >
220+ < TableHeader
221+ align = "right"
222+ tooltip = "Developers with pull requests and push events in the past year"
223+ >
224+ Devs
225+ </ TableHeader >
226+ < TableHeader
227+ align = "right"
228+ tooltip = "Developers with activity (star not included) in this ecosystem (all time)"
229+ >
230+ Contributors
231+ </ TableHeader >
232+ < TableHeader
233+ align = "right"
234+ tooltip = "Developers with first activity in past 90 days"
235+ >
236+ New
237+ </ TableHeader >
238+ < TableHeader
239+ align = "right"
240+ tooltip = "Total repositories in this ecosystem"
241+ >
242+ Repos
243+ </ TableHeader >
196244 </ tr >
197245 </ thead >
198246 < tbody className = "divide-y divide-border dark:divide-border-dark" >
199247 < AnimatePresence mode = "wait" >
200248 { paginatedItems . map ( ( ecosystem , index ) => {
201- const absoluteIndex = ( page - 1 ) * rowsPerPage + index + 1 ;
249+ const globalRank =
250+ ecosystemRanks . get ( ecosystem . eco_name ) || 0 ;
202251 return (
203252 < motion . tr
204253 key = { ecosystem . eco_name }
@@ -209,8 +258,10 @@ export default function EcosystemsPageClient({
209258 >
210259 < td className = "px-6 py-4 whitespace-nowrap" >
211260 < div className = "flex items-center" >
212- < span className = { `inline-flex items-center justify-center w-7 h-7 rounded-full text-xs font-medium transition-all duration-200 group-hover:scale-110 bg-gray-50 dark:bg-surface-dark text-gray-500 dark:text-gray-500` } >
213- { absoluteIndex }
261+ < span
262+ className = { `inline-flex items-center justify-center w-7 h-7 rounded-full text-xs font-medium transition-all duration-200 group-hover:scale-110 bg-gray-50 dark:bg-surface-dark text-gray-500 dark:text-gray-500` }
263+ >
264+ { globalRank }
214265 </ span >
215266 </ div >
216267 </ td >
@@ -252,11 +303,7 @@ export default function EcosystemsPageClient({
252303
253304 { pages > 1 && (
254305 < div className = "px-6 py-4 border-t border-border dark:border-border-dark flex justify-center" >
255- < Pagination
256- page = { page }
257- total = { pages }
258- onChange = { setPage }
259- />
306+ < Pagination page = { page } total = { pages } onChange = { setPage } />
260307 </ div >
261308 ) }
262309 </ Card >
0 commit comments