@playfast/reform-better-hub-ui-primitives 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,236 +1,234 @@
1
- import type * as React from "react";
2
- import { useMemo } from "react";
1
+ import type * as React from 'react'
2
+ import { useMemo } from 'react'
3
3
 
4
- const RNG_MULTIPLIER = 16807;
5
- const RNG_MODULUS = 2147483647;
6
- const RNG_DIVISOR = 2147483646;
7
- const RNG_SEED = 42;
8
- const WEEKS = 52;
9
- const DAYS_PER_WEEK = 7;
10
- const CELL = 15;
11
- const CELL_RECT_SIZE = 12;
12
- const CELL_ANIM_WEEK_DELAY = 0.04;
13
- const CELL_ANIM_DAY_DELAY = 0.015;
4
+ const RNG_MULTIPLIER = 16807
5
+ const RNG_MODULUS = 2147483647
6
+ const RNG_DIVISOR = 2147483646
7
+ const RNG_SEED = 42
8
+ const WEEKS = 52
9
+ const DAYS_PER_WEEK = 7
10
+ const CELL = 15
11
+ const CELL_RECT_SIZE = 12
12
+ const CELL_ANIM_WEEK_DELAY = 0.04
13
+ const CELL_ANIM_DAY_DELAY = 0.015
14
14
 
15
15
  const LEVELS = [
16
- "rgba(255,255,255,0.02)",
17
- "rgba(255,255,255,0.10)",
18
- "rgba(255,255,255,0.18)",
19
- "rgba(255,255,255,0.28)",
20
- "rgba(255,255,255,0.40)",
21
- ];
16
+ 'rgba(255,255,255,0.02)',
17
+ 'rgba(255,255,255,0.10)',
18
+ 'rgba(255,255,255,0.18)',
19
+ 'rgba(255,255,255,0.28)',
20
+ 'rgba(255,255,255,0.40)',
21
+ ]
22
22
 
23
- const LEVEL_THRESHOLDS = [0.3, 0.5, 0.7, 0.85];
23
+ const LEVEL_THRESHOLDS = [0.3, 0.5, 0.7, 0.85]
24
24
 
25
25
  const COMMIT_GROUPS = [
26
- {
27
- prefix: "m",
28
- cx: 200,
29
- radius: 4,
30
- fill: "rgba(255,255,255,0.25)",
31
- ys: [80, 150, 230, 300, 400, 480, 550, 620, 690, 770, 850],
32
- animBase: 0.5,
33
- animStep: 0.15,
34
- },
35
- {
36
- prefix: "f1",
37
- cx: 280,
38
- radius: 3.5,
39
- fill: "rgba(255,255,255,0.20)",
40
- ys: [230, 280, 330],
41
- animBase: 1.0,
42
- animStep: 0.2,
43
- },
44
- {
45
- prefix: "f2",
46
- cx: 130,
47
- radius: 3.5,
48
- fill: "rgba(255,255,255,0.18)",
49
- ys: [360, 420, 470],
50
- animBase: 1.5,
51
- animStep: 0.2,
52
- },
53
- {
54
- prefix: "hf",
55
- cx: 260,
56
- radius: 3,
57
- fill: "rgba(255,255,255,0.15)",
58
- ys: [600, 630, 660],
59
- animBase: 2.0,
60
- animStep: 0.2,
61
- },
62
- {
63
- prefix: "f3",
64
- cx: 110,
65
- radius: 3,
66
- fill: "rgba(255,255,255,0.12)",
67
- ys: [680, 730, 780],
68
- animBase: 2.4,
69
- animStep: 0.2,
70
- },
71
- ];
26
+ {
27
+ prefix: 'm',
28
+ cx: 200,
29
+ radius: 4,
30
+ fill: 'rgba(255,255,255,0.25)',
31
+ ys: [80, 150, 230, 300, 400, 480, 550, 620, 690, 770, 850],
32
+ animBase: 0.5,
33
+ animStep: 0.15,
34
+ },
35
+ {
36
+ prefix: 'f1',
37
+ cx: 280,
38
+ radius: 3.5,
39
+ fill: 'rgba(255,255,255,0.20)',
40
+ ys: [230, 280, 330],
41
+ animBase: 1.0,
42
+ animStep: 0.2,
43
+ },
44
+ {
45
+ prefix: 'f2',
46
+ cx: 130,
47
+ radius: 3.5,
48
+ fill: 'rgba(255,255,255,0.18)',
49
+ ys: [360, 420, 470],
50
+ animBase: 1.5,
51
+ animStep: 0.2,
52
+ },
53
+ {
54
+ prefix: 'hf',
55
+ cx: 260,
56
+ radius: 3,
57
+ fill: 'rgba(255,255,255,0.15)',
58
+ ys: [600, 630, 660],
59
+ animBase: 2.0,
60
+ animStep: 0.2,
61
+ },
62
+ {
63
+ prefix: 'f3',
64
+ cx: 110,
65
+ radius: 3,
66
+ fill: 'rgba(255,255,255,0.12)',
67
+ ys: [680, 730, 780],
68
+ animBase: 2.4,
69
+ animStep: 0.2,
70
+ },
71
+ ]
72
72
 
73
- const nextSeed = (seed: number) => (seed * RNG_MULTIPLIER) % RNG_MODULUS;
74
- const seedToUnit = (seed: number) => (seed - 1) / RNG_DIVISOR;
73
+ const nextSeed = (seed: number) => (seed * RNG_MULTIPLIER) % RNG_MODULUS
74
+ const seedToUnit = (seed: number) => (seed - 1) / RNG_DIVISOR
75
75
  const levelForValue = (sample: number) =>
76
- LEVEL_THRESHOLDS.filter((threshold) => sample >= threshold).length;
76
+ LEVEL_THRESHOLDS.filter((threshold) => sample >= threshold).length
77
77
 
78
- type Cell = { week: number; day: number; level: number };
78
+ type Cell = { week: number; day: number; level: number }
79
79
 
80
80
  export function GitHubBackground(): React.JSX.Element {
81
- const grid = useMemo<Cell[]>(
82
- () =>
83
- Array.from({ length: WEEKS * DAYS_PER_WEEK }).reduce<{
84
- seed: number;
85
- cells: Cell[];
86
- }>(
87
- (acc, _slot, flatIndex) => {
88
- const seed = nextSeed(acc.seed);
89
- const level = levelForValue(seedToUnit(seed));
90
- const week = Math.floor(flatIndex / DAYS_PER_WEEK);
91
- const day = flatIndex % DAYS_PER_WEEK;
92
- return { seed, cells: [...acc.cells, { week, day, level }] };
93
- },
94
- { seed: RNG_SEED, cells: [] },
95
- ).cells,
96
- [],
97
- );
81
+ const grid = useMemo<Cell[]>(
82
+ () =>
83
+ Array.from({ length: WEEKS * DAYS_PER_WEEK }).reduce<{
84
+ seed: number
85
+ cells: Cell[]
86
+ }>(
87
+ (acc, _slot, flatIndex) => {
88
+ const seed = nextSeed(acc.seed)
89
+ const level = levelForValue(seedToUnit(seed))
90
+ const week = Math.floor(flatIndex / DAYS_PER_WEEK)
91
+ const day = flatIndex % DAYS_PER_WEEK
92
+ return { seed, cells: [...acc.cells, { week, day, level }] }
93
+ },
94
+ { seed: RNG_SEED, cells: [] },
95
+ ).cells,
96
+ [],
97
+ )
98
98
 
99
- return (
100
- <div
101
- className="absolute inset-0 pointer-events-none overflow-hidden"
102
- style={{ zIndex: 2 }}
103
- >
104
- <div
105
- className="absolute inset-0"
106
- style={{
107
- maskImage: "radial-gradient(ellipse 85% 75% at 45% 35%, black 15%, transparent 60%)",
108
- WebkitMaskImage:
109
- "radial-gradient(ellipse 85% 75% at 45% 35%, black 15%, transparent 60%)",
110
- }}
111
- >
112
- <div
113
- className="absolute"
114
- style={{
115
- top: "8%",
116
- left: "50%",
117
- transform: "translate(-50%, 0) perspective(500px) rotateX(30deg) rotateZ(-2deg) scale(1.3)",
118
- transformOrigin: "center top",
119
- opacity: 0.4,
120
- }}
121
- >
122
- <svg
123
- width={WEEKS * CELL}
124
- height={DAYS_PER_WEEK * CELL}
125
- viewBox={`0 0 ${WEEKS * CELL} ${DAYS_PER_WEEK * CELL}`}
126
- >
127
- {grid.map((cell, index) => (
128
- <rect
129
- key={index}
130
- x={cell.week * CELL}
131
- y={cell.day * CELL}
132
- width={CELL_RECT_SIZE}
133
- height={CELL_RECT_SIZE}
134
- rx={2}
135
- fill={LEVELS[cell.level]}
136
- opacity={0}
137
- >
138
- <animate
139
- attributeName="opacity"
140
- from="0"
141
- to="1"
142
- dur="0.5s"
143
- begin={`${cell.week * CELL_ANIM_WEEK_DELAY + cell.day * CELL_ANIM_DAY_DELAY}s`}
144
- fill="freeze"
145
- />
146
- </rect>
147
- ))}
148
- </svg>
149
- </div>
99
+ return (
100
+ <div className="absolute inset-0 pointer-events-none overflow-hidden" style={{ zIndex: 2 }}>
101
+ <div
102
+ className="absolute inset-0"
103
+ style={{
104
+ maskImage: 'radial-gradient(ellipse 85% 75% at 45% 35%, black 15%, transparent 60%)',
105
+ WebkitMaskImage:
106
+ 'radial-gradient(ellipse 85% 75% at 45% 35%, black 15%, transparent 60%)',
107
+ }}
108
+ >
109
+ <div
110
+ className="absolute"
111
+ style={{
112
+ top: '8%',
113
+ left: '50%',
114
+ transform:
115
+ 'translate(-50%, 0) perspective(500px) rotateX(30deg) rotateZ(-2deg) scale(1.3)',
116
+ transformOrigin: 'center top',
117
+ opacity: 0.4,
118
+ }}
119
+ >
120
+ <svg
121
+ width={WEEKS * CELL}
122
+ height={DAYS_PER_WEEK * CELL}
123
+ viewBox={`0 0 ${WEEKS * CELL} ${DAYS_PER_WEEK * CELL}`}
124
+ >
125
+ {grid.map((cell, index) => (
126
+ <rect
127
+ key={index}
128
+ x={cell.week * CELL}
129
+ y={cell.day * CELL}
130
+ width={CELL_RECT_SIZE}
131
+ height={CELL_RECT_SIZE}
132
+ rx={2}
133
+ fill={LEVELS[cell.level]}
134
+ opacity={0}
135
+ >
136
+ <animate
137
+ attributeName="opacity"
138
+ from="0"
139
+ to="1"
140
+ dur="0.5s"
141
+ begin={`${cell.week * CELL_ANIM_WEEK_DELAY + cell.day * CELL_ANIM_DAY_DELAY}s`}
142
+ fill="freeze"
143
+ />
144
+ </rect>
145
+ ))}
146
+ </svg>
147
+ </div>
150
148
 
151
- <svg
152
- className="absolute inset-0 w-full h-full"
153
- viewBox="0 0 400 900"
154
- preserveAspectRatio="xMidYMid slice"
155
- style={{ opacity: 0.45 }}
156
- >
157
- <line
158
- x1="200"
159
- y1="0"
160
- x2="200"
161
- y2="900"
162
- stroke="rgba(255,255,255,0.15)"
163
- strokeWidth="2"
164
- pathLength={1}
165
- className="git-line-anim"
166
- style={{ animationDelay: "0.3s" }}
167
- />
149
+ <svg
150
+ className="absolute inset-0 w-full h-full"
151
+ viewBox="0 0 400 900"
152
+ preserveAspectRatio="xMidYMid slice"
153
+ style={{ opacity: 0.45 }}
154
+ >
155
+ <line
156
+ x1="200"
157
+ y1="0"
158
+ x2="200"
159
+ y2="900"
160
+ stroke="rgba(255,255,255,0.15)"
161
+ strokeWidth="2"
162
+ pathLength={1}
163
+ className="git-line-anim"
164
+ style={{ animationDelay: '0.3s' }}
165
+ />
168
166
 
169
- <path
170
- d="M 200 150 C 200 180, 280 200, 280 230 L 280 350 C 280 380, 200 395, 200 400"
171
- stroke="rgba(255,255,255,0.12)"
172
- strokeWidth="2"
173
- fill="none"
174
- pathLength={1}
175
- className="git-line-anim"
176
- style={{ animationDelay: "0.8s" }}
177
- />
167
+ <path
168
+ d="M 200 150 C 200 180, 280 200, 280 230 L 280 350 C 280 380, 200 395, 200 400"
169
+ stroke="rgba(255,255,255,0.12)"
170
+ strokeWidth="2"
171
+ fill="none"
172
+ pathLength={1}
173
+ className="git-line-anim"
174
+ style={{ animationDelay: '0.8s' }}
175
+ />
178
176
 
179
- <path
180
- d="M 200 300 C 200 325, 130 340, 130 360 L 130 500 C 130 525, 200 540, 200 550"
181
- stroke="rgba(255,255,255,0.10)"
182
- strokeWidth="2"
183
- fill="none"
184
- pathLength={1}
185
- className="git-line-anim"
186
- style={{ animationDelay: "1.3s" }}
187
- />
177
+ <path
178
+ d="M 200 300 C 200 325, 130 340, 130 360 L 130 500 C 130 525, 200 540, 200 550"
179
+ stroke="rgba(255,255,255,0.10)"
180
+ strokeWidth="2"
181
+ fill="none"
182
+ pathLength={1}
183
+ className="git-line-anim"
184
+ style={{ animationDelay: '1.3s' }}
185
+ />
188
186
 
189
- <path
190
- d="M 200 550 C 200 570, 260 580, 260 600 L 260 650 C 260 670, 200 680, 200 690"
191
- stroke="rgba(255,255,255,0.08)"
192
- strokeWidth="2"
193
- fill="none"
194
- pathLength={1}
195
- className="git-line-anim"
196
- style={{ animationDelay: "1.8s" }}
197
- />
187
+ <path
188
+ d="M 200 550 C 200 570, 260 580, 260 600 L 260 650 C 260 670, 200 680, 200 690"
189
+ stroke="rgba(255,255,255,0.08)"
190
+ strokeWidth="2"
191
+ fill="none"
192
+ pathLength={1}
193
+ className="git-line-anim"
194
+ style={{ animationDelay: '1.8s' }}
195
+ />
198
196
 
199
- <path
200
- d="M 200 620 C 200 640, 110 660, 110 680 L 110 800 C 110 820, 200 835, 200 850"
201
- stroke="rgba(255,255,255,0.07)"
202
- strokeWidth="2"
203
- fill="none"
204
- pathLength={1}
205
- className="git-line-anim"
206
- style={{ animationDelay: "2.2s" }}
207
- />
197
+ <path
198
+ d="M 200 620 C 200 640, 110 660, 110 680 L 110 800 C 110 820, 200 835, 200 850"
199
+ stroke="rgba(255,255,255,0.07)"
200
+ strokeWidth="2"
201
+ fill="none"
202
+ pathLength={1}
203
+ className="git-line-anim"
204
+ style={{ animationDelay: '2.2s' }}
205
+ />
208
206
 
209
- {COMMIT_GROUPS.map((group) =>
210
- group.ys.map((nodeY, index) => (
211
- <circle
212
- key={`${group.prefix}${index}`}
213
- cx={group.cx}
214
- cy={nodeY}
215
- r={group.radius}
216
- fill={group.fill}
217
- opacity={0}
218
- >
219
- <animate
220
- attributeName="opacity"
221
- from="0"
222
- to="1"
223
- dur="0.3s"
224
- begin={`${group.animBase + index * group.animStep}s`}
225
- fill="freeze"
226
- />
227
- </circle>
228
- )),
229
- )}
230
- </svg>
231
- </div>
207
+ {COMMIT_GROUPS.map((group) =>
208
+ group.ys.map((nodeY, index) => (
209
+ <circle
210
+ key={`${group.prefix}${index}`}
211
+ cx={group.cx}
212
+ cy={nodeY}
213
+ r={group.radius}
214
+ fill={group.fill}
215
+ opacity={0}
216
+ >
217
+ <animate
218
+ attributeName="opacity"
219
+ from="0"
220
+ to="1"
221
+ dur="0.3s"
222
+ begin={`${group.animBase + index * group.animStep}s`}
223
+ fill="freeze"
224
+ />
225
+ </circle>
226
+ )),
227
+ )}
228
+ </svg>
229
+ </div>
232
230
 
233
- <style>{`
231
+ <style>{`
234
232
  .git-line-anim {
235
233
  stroke-dasharray: 1;
236
234
  stroke-dashoffset: 1;
@@ -240,6 +238,6 @@ export function GitHubBackground(): React.JSX.Element {
240
238
  to { stroke-dashoffset: 0; }
241
239
  }
242
240
  `}</style>
243
- </div>
244
- );
241
+ </div>
242
+ )
245
243
  }