@@ -59,7 +59,7 @@ type TimeRange =
59
59
| '1825-days'
60
60
| 'all-time'
61
61
62
- type BinningOption = 'monthly' | 'weekly' | 'daily'
62
+ type BinningOption = 'monthly' | 'weekly' | 'daily' | 'yearly'
63
63
64
64
type NpmPackage = {
65
65
name : string
@@ -451,6 +451,9 @@ function NpmStatsChart({
451
451
let binnedDate = date
452
452
453
453
switch ( binningOption ) {
454
+ case 'yearly' :
455
+ binnedDate = d3 . timeYear . floor ( date )
456
+ break
454
457
case 'monthly' :
455
458
binnedDate = d3 . timeMonth . floor ( date )
456
459
break
@@ -624,6 +627,12 @@ function NpmStatsChart({
624
627
return d3 . timeFormat ( '%b %d' ) ( d )
625
628
case '7-days' :
626
629
return d3 . timeFormat ( '%a' ) ( d )
630
+ case '730-days' :
631
+ case '1825-days' :
632
+ case 'all-time' :
633
+ return binningOption === 'yearly'
634
+ ? d3 . timeFormat ( '%Y' ) ( d )
635
+ : d3 . timeFormat ( '%b %Y' ) ( d )
627
636
default :
628
637
return d3 . timeFormat ( '%x' ) ( d )
629
638
}
@@ -704,7 +713,7 @@ export const Route = createFileRoute('/stats/npm/')({
704
713
. default ( '7-days' ) ,
705
714
baseline : z . string ( ) . optional ( ) ,
706
715
viewMode : z . enum ( [ 'absolute' , 'relative' ] ) . optional ( ) ,
707
- binningOption : z . enum ( [ 'monthly' , 'weekly' , 'daily' ] ) . optional ( ) ,
716
+ binningOption : z . enum ( [ 'yearly' , ' monthly', 'weekly' , 'daily' ] ) . optional ( ) ,
708
717
alignStartDates : z . boolean ( ) . optional ( ) . default ( false ) ,
709
718
} ) ,
710
719
loaderDeps : ( { search } ) => ( {
@@ -877,9 +886,9 @@ function RouteComponent() {
877
886
case '730-days' :
878
887
return 'monthly'
879
888
case '1825-days' :
880
- return 'monthly '
889
+ return 'yearly '
881
890
case 'all-time' :
882
- return 'monthly '
891
+ return 'yearly '
883
892
}
884
893
} ) ( )
885
894
@@ -1010,10 +1019,10 @@ function RouteComponent() {
1010
1019
setBinningOption ( 'monthly' )
1011
1020
break
1012
1021
case '1825-days' :
1013
- setBinningOption ( 'monthly ' )
1022
+ setBinningOption ( 'yearly ' )
1014
1023
break
1015
1024
case 'all-time' :
1016
- setBinningOption ( 'monthly ' )
1025
+ setBinningOption ( 'yearly ' )
1017
1026
break
1018
1027
}
1019
1028
@@ -1037,7 +1046,9 @@ function RouteComponent() {
1037
1046
} )
1038
1047
}
1039
1048
1040
- const handleBinnedChange = ( value : 'daily' | 'weekly' | 'monthly' ) => {
1049
+ const handleBinnedChange = (
1050
+ value : 'daily' | 'weekly' | 'monthly' | 'yearly'
1051
+ ) => {
1041
1052
navigate ( {
1042
1053
to : '.' ,
1043
1054
search : ( prev ) => ( {
@@ -1152,10 +1163,22 @@ function RouteComponent() {
1152
1163
</ Tooltip >
1153
1164
</ div >
1154
1165
< div className = "flex items-stretch bg-gray-500/10 rounded-md" >
1166
+ < Tooltip content = "Group data by year" >
1167
+ < button
1168
+ onClick = { ( ) => handleBinnedChange ( 'yearly' ) }
1169
+ className = { `px-3 py-1.5 rounded-l ${
1170
+ binningOption === 'yearly'
1171
+ ? 'bg-cyan-500 text-white'
1172
+ : 'hover:bg-gray-500/20'
1173
+ } `}
1174
+ >
1175
+ Yearly
1176
+ </ button >
1177
+ </ Tooltip >
1155
1178
< Tooltip content = "Group data by month" >
1156
1179
< button
1157
1180
onClick = { ( ) => handleBinnedChange ( 'monthly' ) }
1158
- className = { `px-3 py-1.5 rounded-l ${
1181
+ className = { `px-3 py-1.5 ${
1159
1182
binningOption === 'monthly'
1160
1183
? 'bg-cyan-500 text-white'
1161
1184
: 'hover:bg-gray-500/20'
0 commit comments