1
1
'use client'
2
2
3
+ import { useQuery } from '@tanstack/react-query'
4
+
3
5
import { useOnlineCount } from '~/atoms'
4
6
import { useSocketIsConnect } from '~/atoms/hooks'
5
7
import { ImpressionView } from '~/components/common/ImpressionTracker'
@@ -8,14 +10,18 @@ import { FloatPopover } from '~/components/ui/float-popover'
8
10
import { NumberSmoothTransition } from '~/components/ui/number-transition/NumberSmoothTransition'
9
11
import { TrackerAction } from '~/constants/tracker'
10
12
import { usePageIsActive } from '~/hooks/common/use-is-active'
13
+ import { apiClient } from '~/lib/request'
14
+ import { routeBuilder , Routes } from '~/lib/route-builder'
11
15
12
- export const GatewayCount = ( ) => {
16
+ const Help = ( ) => {
13
17
return (
14
18
< FloatPopover
15
19
as = "span"
16
- TriggerComponent = { GatewayCountTrigger }
20
+ triggerElement = {
21
+ < i className = "icon-[mingcute--question-line] cursor-help" />
22
+ }
17
23
type = "tooltip"
18
- wrapperClassName = "cursor-help"
24
+ asChild
19
25
>
20
26
< div className = "space-y-2 leading-relaxed" >
21
27
< p className = "flex items-center space-x-1 opacity-80" >
@@ -77,18 +83,112 @@ const ConnectedIndicator = () => {
77
83
)
78
84
}
79
85
80
- const GatewayCountTrigger = ( ) => {
86
+ export const GatewayCount = ( ) => {
81
87
const isActive = usePageIsActive ( )
82
88
const count = useOnlineCount ( )
83
89
84
90
if ( ! isActive ) return null
85
91
return (
86
- < span key = { count } >
87
- 正在被{ ' ' }
88
- < span >
89
- < NumberSmoothTransition > { count } </ NumberSmoothTransition >
90
- </ span > { ' ' }
91
- 人看爆
92
- </ span >
92
+ < div className = "inline-flex items-center gap-2" >
93
+ < FloatPopover
94
+ asChild
95
+ placement = "top"
96
+ offset = { 10 }
97
+ triggerElement = {
98
+ < span key = { count } className = "cursor-pointer" >
99
+ 正在被{ ' ' }
100
+ < span >
101
+ < NumberSmoothTransition > { count } </ NumberSmoothTransition >
102
+ </ span > { ' ' }
103
+ 人看爆
104
+ </ span >
105
+ }
106
+ >
107
+ < RoomsInfo />
108
+ </ FloatPopover >
109
+ < Help />
110
+ </ div >
111
+ )
112
+ }
113
+
114
+ const RoomsInfo = ( ) => {
115
+ const { data } = useQuery ( {
116
+ queryKey : [ 'rooms' ] ,
117
+ refetchOnMount : true ,
118
+ queryFn : ( ) => {
119
+ return apiClient . activity
120
+ . getRoomsInfo ( )
121
+ . then ( ( res ) => res . $serialized )
122
+ . then ( ( data ) => {
123
+ const result = [ ] as {
124
+ path : string
125
+ title : string
126
+ count : number
127
+ } [ ]
128
+
129
+ const morphArticleIdToRoomName = ( id : string ) => `article_${ id } `
130
+ data . objects . notes . forEach ( ( note ) => {
131
+ result . push ( {
132
+ path : routeBuilder ( Routes . Note , {
133
+ id : note . nid ,
134
+ } ) ,
135
+ title : note . title ,
136
+ count : data . roomCount [ morphArticleIdToRoomName ( note . id ) ] ,
137
+ } )
138
+ } )
139
+
140
+ data . objects . posts . forEach ( ( post ) => {
141
+ result . push ( {
142
+ path : routeBuilder ( Routes . Post , {
143
+ category : post . category . slug ,
144
+ slug : post . slug ,
145
+ } ) ,
146
+ title : post . title ,
147
+ count : data . roomCount [ morphArticleIdToRoomName ( post . id ) ] ,
148
+ } )
149
+ } )
150
+
151
+ data . objects . pages . forEach ( ( page ) => {
152
+ result . push ( {
153
+ path : routeBuilder ( Routes . Page , {
154
+ slug : page . slug ,
155
+ } ) ,
156
+ title : page . title ,
157
+ count : data . roomCount [ morphArticleIdToRoomName ( page . id ) ] ,
158
+ } )
159
+ } )
160
+
161
+ return result . sort ( ( a , b ) => b . count - a . count )
162
+ } )
163
+ } ,
164
+ } )
165
+
166
+ if ( ! data ) return < div className = "loading loading-spinner" />
167
+ if ( data . length === 0 )
168
+ return < div className = "text-gray-500" > 还没有人在偷偷观察哦~</ div >
169
+ return (
170
+ < div className = "max-w-[80vw] lg:max-w-[400px]" >
171
+ < div className = "mb-2 text-sm font-medium" > 下面的内容正在被看爆:</ div >
172
+ < ul className = "flex flex-col justify-between gap-2" >
173
+ { data . map ( ( room ) => (
174
+ < li key = { room . path } className = "flex items-center justify-between" >
175
+ < a
176
+ target = "_blank"
177
+ href = { room . path }
178
+ className = "hover:underline"
179
+ rel = "noreferrer"
180
+ >
181
+ { room . title }
182
+ </ a >
183
+ { ! ! room . count && (
184
+ < span className = "ml-5 inline-flex items-center text-sm text-gray-500" >
185
+ < i className = "icon-[mingcute--user-visible-line]" /> { ' ' }
186
+ { room . count }
187
+ </ span >
188
+ ) }
189
+ </ li >
190
+ ) ) }
191
+ </ ul >
192
+ </ div >
93
193
)
94
194
}
0 commit comments