1
+ import Graph1 from "@/assets/images/brand/decor/git/graph-1" ;
2
+ import Graph2 from "@/assets/images/brand/decor/git/graph-2" ;
3
+ import Graph3 from "@/assets/images/brand/decor/git/graph-3" ;
4
+ import Graph4 from "@/assets/images/brand/decor/git/graph-4" ;
5
+ import useSSGSafe from "@/hooks/useSSGSafe" ;
6
+
7
+ import React , { useMemo , useRef } from "react" ;
8
+
9
+ export interface GraphDecorProps {
10
+
11
+ }
12
+
13
+ const colors = [
14
+ "#DC2626" ,
15
+ "#2563EB" ,
16
+ "#7C3AED" ,
17
+ "#A3E635" ,
18
+ "#F59E0B"
19
+ ] ;
20
+
21
+ const makeColorBrush = ( ) => {
22
+ const notChosenColors = [ ...colors ] ;
23
+
24
+ return ( ) => {
25
+ const colorPool = notChosenColors . length === 0 ? colors : notChosenColors ;
26
+ const chosenIndex = Math . floor ( Math . random ( ) * colorPool . length ) ;
27
+ const color = colorPool [ chosenIndex ] ;
28
+
29
+ if ( notChosenColors . length !== 0 ) {
30
+ notChosenColors . splice ( chosenIndex , 1 ) ;
31
+ }
32
+
33
+ return color ;
34
+ } ;
35
+ } ;
36
+
37
+ const getSide = ( perviousSides : boolean [ ] ) => {
38
+ if ( perviousSides . length === 0 ) {
39
+ const side = Math . random ( ) > 0.5 ;
40
+ perviousSides . unshift ( side ) ;
41
+ return side ;
42
+ } ;
43
+
44
+ const samePreviousSides = perviousSides . every ( ( value , i , arr ) => i === 0 || value === arr [ i - 1 ] ) ;
45
+ const side = samePreviousSides ? ! perviousSides . at ( 0 ) ! : Math . random ( ) > 0.5 ;
46
+
47
+ perviousSides . unshift ( side ) ;
48
+ perviousSides . length > 2 && perviousSides . pop ( ) ;
49
+
50
+ return side ;
51
+ } ;
52
+
53
+ const decors = [
54
+ {
55
+ name : "1" ,
56
+ widthMultiplier : 2 ,
57
+ aspect : 1900 / 600 ,
58
+ component : ( { makeColor, ...props } ) => (
59
+ < Graph1
60
+ { ...props }
61
+ color = { makeColor ( ) }
62
+ color1 = { makeColor ( ) }
63
+ />
64
+ )
65
+ } ,
66
+ {
67
+ name : "2" ,
68
+ widthMultiplier : 1 ,
69
+ aspect : 1600 / 300 ,
70
+ component : ( { makeColor, ...props } ) => (
71
+ < Graph2
72
+ { ...props }
73
+ color = { makeColor ( ) }
74
+ />
75
+ )
76
+ } ,
77
+ {
78
+ name : "3" ,
79
+ widthMultiplier : 1 ,
80
+ aspect : 2500 / 300 ,
81
+ component : ( { makeColor, ...props } ) => (
82
+ < Graph3
83
+ { ...props }
84
+ color = { makeColor ( ) }
85
+ />
86
+ )
87
+ } ,
88
+ {
89
+ name : "4" ,
90
+ widthMultiplier : 1 ,
91
+ aspect : 2800 / 300 ,
92
+ component : ( { makeColor, ...props } ) => (
93
+ < Graph4
94
+ { ...props }
95
+ color = { makeColor ( ) }
96
+ color1 = { makeColor ( ) }
97
+ />
98
+ )
99
+ }
100
+ ] as {
101
+ name : string ;
102
+ widthMultiplier : number ;
103
+ aspect : number ;
104
+ component : React . ComponentType < Omit < React . ComponentProps < "svg" > , "ref" > & { makeColor : ( ) => string ; } > ;
105
+ } [ ] ;
106
+
107
+ const AMOUNT = 40 ;
108
+
109
+ const GraphDecor = ( { } : GraphDecorProps ) => {
110
+ const isSafe = useSSGSafe ( ) ;
111
+
112
+ const renderedGraphs = useMemo ( ( ) => {
113
+ if ( ! isSafe ) return ;
114
+
115
+ const controls = {
116
+ currentLength : 60 , // rem
117
+ perviousSides : [ ] as boolean [ ] // last 2 sides
118
+ } ;
119
+
120
+ return Array ( AMOUNT ) . fill ( true ) . map ( ( _ , i ) => {
121
+ const decor = decors [ Math . floor ( Math . random ( ) * decors . length ) ] ;
122
+ const side = getSide ( controls . perviousSides ) ;
123
+
124
+ const width = 10 * decor . widthMultiplier ; // rem
125
+ const height = width * decor . aspect ;
126
+ const padding = Math . random ( ) * 40 + 20 ;
127
+ const style = { "--width-mulitplier" : decor . widthMultiplier , "--length" : `${ controls . currentLength } rem` } as React . CSSProperties ;
128
+
129
+ controls . currentLength += ( height + padding ) * 1.5 ;
130
+
131
+ return (
132
+ < decor . component
133
+ key = { i }
134
+ makeColor = { makeColorBrush ( ) }
135
+ style = { style }
136
+ className = { `absolute opacity-10 w-[calc(var(--width)_*_var(--width-mulitplier))] top-[var(--length)] [--width:10rem] md:[--width:6rem] motion-safe:transition-all ${ side ? "left-0 -scale-100" : "right-0" } ` }
137
+ />
138
+ ) ;
139
+ } ) ;
140
+ } , [ isSafe ] ) ;
141
+
142
+ return (
143
+ < div className = "absolute inset-0 overflow-hidden" >
144
+ { isSafe && < >
145
+ { renderedGraphs }
146
+ </ > }
147
+ </ div >
148
+ ) ;
149
+ } ;
150
+
151
+ export default React . memo ( GraphDecor ) ;
0 commit comments