@@ -3,6 +3,8 @@ import { useServerInsertedHTML } from 'next/navigation'
3
3
import type { AccentColor } from '~/app/config'
4
4
import type { PropsWithChildren } from 'react'
5
5
6
+ import { useEventCallback } from '~/hooks/common/use-event-callback'
7
+ import { debounce } from '~/lib/_'
6
8
import { generateTransitionColors , hexToHsl } from '~/lib/color'
7
9
import { noopObj } from '~/lib/noop'
8
10
@@ -27,8 +29,12 @@ const accentColorDark = [
27
29
'#838BC6' ,
28
30
]
29
31
32
+ const isSafari = ( ) =>
33
+ / ^ ( (? ! c h r o m e | a n d r o i d ) .) * s a f a r i / i. test ( navigator . userAgent )
34
+
30
35
const STEP = 60
31
- const INTERVAL = 300
36
+ const INTERVAL = 500
37
+
32
38
export const AccentColorProvider = ( { children } : PropsWithChildren ) => {
33
39
const { light, dark } =
34
40
useAppConfigSelector ( ( config ) => config . color ) || ( noopObj as AccentColor )
@@ -42,7 +48,7 @@ export const AccentColorProvider = ({ children }: PropsWithChildren) => {
42
48
const currentAccentColorDRef = useRef ( darkColors [ randomSeedRef . current ] )
43
49
44
50
const [ u , update ] = useState ( 0 )
45
- useEffect ( ( ) => {
51
+ const updateColorEvent = useEventCallback ( ( ) => {
46
52
const $style = document . createElement ( 'style' )
47
53
48
54
const nextSeed = ( randomSeedRef . current + 1 ) % Length
@@ -59,13 +65,17 @@ export const AccentColorProvider = ({ children }: PropsWithChildren) => {
59
65
STEP ,
60
66
)
61
67
62
- const timer = setTimeout ( function updateAccent ( ) {
68
+ let timerDispose = setIdleTimeout ( function updateAccent ( ) {
63
69
const colorD = colorsD . shift ( )
64
70
const colorL = colorsL . shift ( )
65
71
if ( colorD && colorL ) {
66
72
currentAccentColorDRef . current = colorD
67
73
currentAccentColorLRef . current = colorL
68
- setTimeout ( updateAccent , INTERVAL )
74
+
75
+ try {
76
+ timerDispose ( )
77
+ } catch { }
78
+ timerDispose = setIdleTimeout ( updateAccent , INTERVAL )
69
79
} else {
70
80
randomSeedRef . current = nextSeed
71
81
currentAccentColorDRef . current = nextColorD
@@ -92,13 +102,18 @@ export const AccentColorProvider = ({ children }: PropsWithChildren) => {
92
102
93
103
document . head . appendChild ( $style )
94
104
return ( ) => {
95
- clearTimeout ( timer )
105
+ timerDispose ( )
96
106
97
107
setTimeout ( ( ) => {
98
108
document . head . removeChild ( $style )
99
109
} , INTERVAL )
100
110
}
101
- } , [ Length , darkColors , lightColors , u ] )
111
+ } )
112
+ useEffect ( ( ) => {
113
+ // safari 性能不行
114
+ if ( isSafari ( ) ) return
115
+ return updateColorEvent ( )
116
+ } , [ Length , darkColors , lightColors , u , updateColorEvent ] )
102
117
103
118
useServerInsertedHTML ( ( ) => {
104
119
const lightHsl = hexToHsl ( currentAccentColorLRef . current )
@@ -129,3 +144,38 @@ export const AccentColorProvider = ({ children }: PropsWithChildren) => {
129
144
130
145
return children
131
146
}
147
+
148
+ function setIdleTimeout ( onIdle : ( ) => void , timeout : number ) : ( ) => void {
149
+ let timeoutId : number | undefined
150
+
151
+ const debounceReset = debounce ( ( ) => {
152
+ clearTimeout ( timeoutId )
153
+ timeoutId = window . setTimeout ( ( ) => {
154
+ onIdle ( )
155
+ } , timeout )
156
+ } , 100 )
157
+
158
+ // 重置计时器的函数
159
+ const resetTimer = ( ) => {
160
+ window . clearTimeout ( timeoutId )
161
+ debounceReset ( )
162
+ }
163
+
164
+ // 监听浏览器的活动事件
165
+ window . addEventListener ( 'mousemove' , resetTimer )
166
+ window . addEventListener ( 'keypress' , resetTimer )
167
+ window . addEventListener ( 'touchstart' , resetTimer )
168
+ window . addEventListener ( 'scroll' , resetTimer )
169
+
170
+ // 启动计时器
171
+ resetTimer ( )
172
+
173
+ // 提供取消功能
174
+ return function cancel ( ) : void {
175
+ window . clearTimeout ( timeoutId )
176
+ window . removeEventListener ( 'mousemove' , resetTimer )
177
+ window . removeEventListener ( 'keypress' , resetTimer )
178
+ window . removeEventListener ( 'touchstart' , resetTimer )
179
+ window . removeEventListener ( 'scroll' , resetTimer )
180
+ }
181
+ }
0 commit comments