1
+ import { useEffect , useRef , useState } from 'react'
1
2
import { useServerInsertedHTML } from 'next/navigation'
2
3
import type { AccentColor } from '~/app/config'
3
4
import type { PropsWithChildren } from 'react'
4
5
5
- import { sample } from '~/lib/_'
6
- import { hexToHsl } from '~/lib/color'
6
+ import { generateTransitionColors , hexToHsl } from '~/lib/color'
7
7
import { noopObj } from '~/lib/noop'
8
8
9
9
import { useAppConfigSelector } from './aggregation-data-provider'
@@ -30,20 +30,91 @@ const accentColorDark = [
30
30
export const AccentColorProvider = ( { children } : PropsWithChildren ) => {
31
31
const { light, dark } =
32
32
useAppConfigSelector ( ( config ) => config . color ) || ( noopObj as AccentColor )
33
- useServerInsertedHTML ( ( ) => {
34
- const accentColorL = sample ( light ?? accentColorLight )
35
- const accentColorD = sample ( dark ?? accentColorDark )
36
33
37
- const lightHsl = hexToHsl ( accentColorL )
38
- const darkHsl = hexToHsl ( accentColorD )
34
+ const Length = Math . max ( light ?. length ?? 0 , dark ?. length ?? 0 )
35
+ const randomSeedRef = useRef ( ( Math . random ( ) * Length ) | 0 )
36
+
37
+ const lightColors = light ?? accentColorLight
38
+ const darkColors = dark ?? accentColorDark
39
+ const currentAccentColorLRef = useRef ( lightColors [ randomSeedRef . current ] )
40
+ const currentAccentColorDRef = useRef ( darkColors [ randomSeedRef . current ] )
41
+
42
+ const [ u , update ] = useState ( 0 )
43
+ useEffect ( ( ) => {
44
+ const $style = document . createElement ( 'style' )
45
+
46
+ const $originColor = document . getElementById ( 'accent-color-style' )
47
+
48
+ const nextSeed = ( randomSeedRef . current + 1 ) % Length
49
+ const nextColorD = darkColors [ nextSeed ]
50
+ const nextColorL = lightColors [ nextSeed ]
51
+ const STEP = 60
52
+ const INTERVAL = 100
53
+ const colorsD = generateTransitionColors (
54
+ currentAccentColorDRef . current ,
55
+ nextColorD ,
56
+ STEP ,
57
+ )
58
+ const colorsL = generateTransitionColors (
59
+ currentAccentColorLRef . current ,
60
+ nextColorL ,
61
+ STEP ,
62
+ )
63
+
64
+ const timer = setTimeout ( function updateAccent ( ) {
65
+ const colorD = colorsD . shift ( )
66
+ const colorL = colorsL . shift ( )
67
+ if ( colorD && colorL ) {
68
+ currentAccentColorDRef . current = colorD
69
+ currentAccentColorLRef . current = colorL
70
+ setTimeout ( updateAccent , INTERVAL )
71
+ } else {
72
+ randomSeedRef . current = nextSeed
73
+ currentAccentColorDRef . current = nextColorD
74
+ currentAccentColorLRef . current = nextColorL
75
+ update ( u + 1 )
76
+ }
77
+
78
+ const lightHsl = hexToHsl ( currentAccentColorLRef . current )
79
+ const darkHsl = hexToHsl ( currentAccentColorDRef . current )
80
+
81
+ const [ hl , sl , ll ] = lightHsl
82
+ const [ hd , sd , ld ] = darkHsl
83
+
84
+ $style . innerHTML = `html[data-theme='light'] {
85
+ --a: ${ `${ hl } ${ sl } % ${ ll } %` } ;
86
+ --af: ${ `${ hl } ${ sl } % ${ ll + 6 } %` } ;
87
+ }
88
+ html[data-theme='dark'] {
89
+ --a: ${ `${ hd } ${ sd } % ${ ld } %` } ;
90
+ --af: ${ `${ hd } ${ sd } % ${ ld - 6 } %` } ;
91
+ }
92
+ `
93
+ } , INTERVAL )
94
+ document . head . appendChild ( $style )
95
+ // FIXME should remove origin color, if not will not override origin color
96
+ $originColor ?. remove ( )
97
+ return ( ) => {
98
+ clearTimeout ( timer )
99
+
100
+ setTimeout ( ( ) => {
101
+ document . head . removeChild ( $style )
102
+ } , 1000 )
103
+ }
104
+ } , [ Length , darkColors , lightColors , u ] )
105
+
106
+ useServerInsertedHTML ( ( ) => {
107
+ const lightHsl = hexToHsl ( currentAccentColorLRef . current )
108
+ const darkHsl = hexToHsl ( currentAccentColorDRef . current )
39
109
40
110
const [ hl , sl , ll ] = lightHsl
41
111
const [ hd , sd , ld ] = darkHsl
42
112
43
113
return (
44
114
< style
45
- data-light = { accentColorL }
46
- data-dark = { accentColorD }
115
+ id = "accent-color-style"
116
+ data-light = { currentAccentColorLRef . current }
117
+ data-dark = { currentAccentColorDRef . current }
47
118
dangerouslySetInnerHTML = { {
48
119
__html : `html[data-theme='light'] {
49
120
--a: ${ `${ hl } ${ sl } % ${ ll } %` } ;
0 commit comments