@gblikas/querykit 0.0.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.
Files changed (118) hide show
  1. package/.cursor/BUGBOT.md +21 -0
  2. package/.cursor/rules/01-project-structure.mdc +77 -0
  3. package/.cursor/rules/02-typescript-standards.mdc +105 -0
  4. package/.cursor/rules/03-testing-standards.mdc +78 -0
  5. package/.cursor/rules/04-query-language.mdc +79 -0
  6. package/.cursor/rules/05-solid-principles.mdc +118 -0
  7. package/.cursor/rules/liqe-readme-docs.mdc +438 -0
  8. package/.devcontainer/devcontainer.json +25 -0
  9. package/.eslintignore +1 -0
  10. package/.eslintrc.js +39 -0
  11. package/.github/dependabot.yml +12 -0
  12. package/.github/workflows/ci.yml +114 -0
  13. package/.github/workflows/publish.yml +61 -0
  14. package/.husky/pre-commit +30 -0
  15. package/.prettierrc +10 -0
  16. package/CONTRIBUTING.md +187 -0
  17. package/LICENSE +674 -0
  18. package/README.md +237 -0
  19. package/dist/adapters/drizzle/index.d.ts +122 -0
  20. package/dist/adapters/drizzle/index.js +166 -0
  21. package/dist/adapters/index.d.ts +7 -0
  22. package/dist/adapters/index.js +25 -0
  23. package/dist/adapters/types.d.ts +60 -0
  24. package/dist/adapters/types.js +8 -0
  25. package/dist/index.d.ts +75 -0
  26. package/dist/index.js +118 -0
  27. package/dist/parser/index.d.ts +2 -0
  28. package/dist/parser/index.js +18 -0
  29. package/dist/parser/parser.d.ts +51 -0
  30. package/dist/parser/parser.js +201 -0
  31. package/dist/parser/types.d.ts +68 -0
  32. package/dist/parser/types.js +5 -0
  33. package/dist/query/builder.d.ts +61 -0
  34. package/dist/query/builder.js +188 -0
  35. package/dist/query/index.d.ts +2 -0
  36. package/dist/query/index.js +18 -0
  37. package/dist/query/types.d.ts +79 -0
  38. package/dist/query/types.js +2 -0
  39. package/dist/security/index.d.ts +2 -0
  40. package/dist/security/index.js +18 -0
  41. package/dist/security/types.d.ts +181 -0
  42. package/dist/security/types.js +43 -0
  43. package/dist/security/validator.d.ts +191 -0
  44. package/dist/security/validator.js +344 -0
  45. package/dist/translators/drizzle/index.d.ts +73 -0
  46. package/dist/translators/drizzle/index.js +260 -0
  47. package/dist/translators/index.d.ts +8 -0
  48. package/dist/translators/index.js +27 -0
  49. package/dist/translators/sql/index.d.ts +108 -0
  50. package/dist/translators/sql/index.js +252 -0
  51. package/dist/translators/types.d.ts +39 -0
  52. package/dist/translators/types.js +8 -0
  53. package/examples/qk-next/README.md +35 -0
  54. package/examples/qk-next/app/favicon.ico +0 -0
  55. package/examples/qk-next/app/globals.css +122 -0
  56. package/examples/qk-next/app/layout.tsx +121 -0
  57. package/examples/qk-next/app/page.tsx +813 -0
  58. package/examples/qk-next/app/providers.tsx +80 -0
  59. package/examples/qk-next/components/aurora-background.tsx +12 -0
  60. package/examples/qk-next/components/github-stars.tsx +51 -0
  61. package/examples/qk-next/components/mode-toggle.tsx +27 -0
  62. package/examples/qk-next/components/reactbits/blocks/Backgrounds/Aurora/Aurora.tsx +217 -0
  63. package/examples/qk-next/components/reactbits/blocks/Backgrounds/LightRays/LightRays.tsx +474 -0
  64. package/examples/qk-next/components/theme-provider.tsx +11 -0
  65. package/examples/qk-next/components/ui/card.tsx +92 -0
  66. package/examples/qk-next/components/ui/command.tsx +184 -0
  67. package/examples/qk-next/components/ui/dialog.tsx +143 -0
  68. package/examples/qk-next/components/ui/drawer.tsx +135 -0
  69. package/examples/qk-next/components/ui/hover-card.tsx +44 -0
  70. package/examples/qk-next/components/ui/icons.tsx +148 -0
  71. package/examples/qk-next/components/ui/sonner.tsx +26 -0
  72. package/examples/qk-next/components/ui/table.tsx +117 -0
  73. package/examples/qk-next/components.json +21 -0
  74. package/examples/qk-next/eslint.config.mjs +21 -0
  75. package/examples/qk-next/jsrepo.json +13 -0
  76. package/examples/qk-next/lib/utils.ts +6 -0
  77. package/examples/qk-next/next.config.ts +8 -0
  78. package/examples/qk-next/package.json +48 -0
  79. package/examples/qk-next/pnpm-lock.yaml +5558 -0
  80. package/examples/qk-next/postcss.config.mjs +5 -0
  81. package/examples/qk-next/public/file.svg +1 -0
  82. package/examples/qk-next/public/globe.svg +1 -0
  83. package/examples/qk-next/public/next.svg +1 -0
  84. package/examples/qk-next/public/vercel.svg +1 -0
  85. package/examples/qk-next/public/window.svg +1 -0
  86. package/examples/qk-next/tsconfig.json +42 -0
  87. package/examples/qk-next/types/sonner.d.ts +3 -0
  88. package/jest.config.js +26 -0
  89. package/package.json +51 -0
  90. package/src/adapters/drizzle/drizzle-adapter.test.ts +115 -0
  91. package/src/adapters/drizzle/index.ts +299 -0
  92. package/src/adapters/index.ts +11 -0
  93. package/src/adapters/types.ts +72 -0
  94. package/src/index.ts +194 -0
  95. package/src/integration.test.ts +202 -0
  96. package/src/parser/index.ts +2 -0
  97. package/src/parser/parser.test.ts +1056 -0
  98. package/src/parser/parser.ts +268 -0
  99. package/src/parser/types.ts +97 -0
  100. package/src/query/builder.test.ts +272 -0
  101. package/src/query/builder.ts +274 -0
  102. package/src/query/index.ts +2 -0
  103. package/src/query/types.ts +107 -0
  104. package/src/security/index.ts +2 -0
  105. package/src/security/types.ts +210 -0
  106. package/src/security/validator.test.ts +459 -0
  107. package/src/security/validator.ts +395 -0
  108. package/src/security.test.ts +366 -0
  109. package/src/translators/drizzle/drizzle-translator.test.ts +128 -0
  110. package/src/translators/drizzle/index.test.ts +45 -0
  111. package/src/translators/drizzle/index.ts +346 -0
  112. package/src/translators/index.ts +14 -0
  113. package/src/translators/sql/index.test.ts +45 -0
  114. package/src/translators/sql/index.ts +331 -0
  115. package/src/translators/sql/sql-translator.test.ts +419 -0
  116. package/src/translators/types.ts +44 -0
  117. package/src/types/sonner.d.ts +3 -0
  118. package/tsconfig.json +34 -0
@@ -0,0 +1,474 @@
1
+ /*
2
+ Installed from https://reactbits.dev/ts/tailwind/
3
+ */
4
+
5
+ import { useRef, useEffect, useState } from 'react';
6
+ import { Renderer, Program, Triangle, Mesh } from 'ogl';
7
+
8
+ export type RaysOrigin =
9
+ | 'top-center'
10
+ | 'top-left'
11
+ | 'top-right'
12
+ | 'right'
13
+ | 'left'
14
+ | 'bottom-center'
15
+ | 'bottom-right'
16
+ | 'bottom-left';
17
+
18
+ interface UniformValue {
19
+ value: number | number[] | boolean;
20
+ }
21
+
22
+ interface Uniforms {
23
+ iTime: UniformValue;
24
+ iResolution: UniformValue;
25
+ rayPos: UniformValue;
26
+ rayDir: UniformValue;
27
+ raysColor: UniformValue;
28
+ raysSpeed: UniformValue;
29
+ lightSpread: UniformValue;
30
+ rayLength: UniformValue;
31
+ pulsating: UniformValue;
32
+ fadeDistance: UniformValue;
33
+ saturation: UniformValue;
34
+ mousePos: UniformValue;
35
+ mouseInfluence: UniformValue;
36
+ noiseAmount: UniformValue;
37
+ distortion: UniformValue;
38
+ }
39
+
40
+ interface LightRaysProps {
41
+ raysOrigin?: RaysOrigin;
42
+ raysColor?: string;
43
+ raysSpeed?: number;
44
+ lightSpread?: number;
45
+ rayLength?: number;
46
+ pulsating?: boolean;
47
+ fadeDistance?: number;
48
+ saturation?: number;
49
+ followMouse?: boolean;
50
+ mouseInfluence?: number;
51
+ noiseAmount?: number;
52
+ distortion?: number;
53
+ className?: string;
54
+ }
55
+
56
+ const DEFAULT_COLOR = '#ffffff';
57
+
58
+ const hexToRgb = (hex: string): [number, number, number] => {
59
+ const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
60
+ return m
61
+ ? [
62
+ parseInt(m[1], 16) / 255,
63
+ parseInt(m[2], 16) / 255,
64
+ parseInt(m[3], 16) / 255
65
+ ]
66
+ : [1, 1, 1];
67
+ };
68
+
69
+ const getAnchorAndDir = (
70
+ origin: RaysOrigin,
71
+ w: number,
72
+ h: number
73
+ ): { anchor: [number, number]; dir: [number, number] } => {
74
+ const outside = 0.2;
75
+ switch (origin) {
76
+ case 'top-left':
77
+ return { anchor: [0, -outside * h], dir: [0, 1] };
78
+ case 'top-right':
79
+ return { anchor: [w, -outside * h], dir: [0, 1] };
80
+ case 'left':
81
+ return { anchor: [-outside * w, 0.5 * h], dir: [1, 0] };
82
+ case 'right':
83
+ return { anchor: [(1 + outside) * w, 0.5 * h], dir: [-1, 0] };
84
+ case 'bottom-left':
85
+ return { anchor: [0, (1 + outside) * h], dir: [0, -1] };
86
+ case 'bottom-center':
87
+ return { anchor: [0.5 * w, (1 + outside) * h], dir: [0, -1] };
88
+ case 'bottom-right':
89
+ return { anchor: [w, (1 + outside) * h], dir: [0, -1] };
90
+ default: // "top-center"
91
+ return { anchor: [0.5 * w, -outside * h], dir: [0, 1] };
92
+ }
93
+ };
94
+
95
+ const LightRays: React.FC<LightRaysProps> = ({
96
+ raysOrigin = 'top-center',
97
+ raysColor = DEFAULT_COLOR,
98
+ raysSpeed = 1,
99
+ lightSpread = 1,
100
+ rayLength = 2,
101
+ pulsating = false,
102
+ fadeDistance = 1.0,
103
+ saturation = 1.0,
104
+ followMouse = true,
105
+ mouseInfluence = 0.1,
106
+ noiseAmount = 0.0,
107
+ distortion = 0.0,
108
+ className = ''
109
+ }) => {
110
+ const containerRef = useRef<HTMLDivElement>(null);
111
+ const uniformsRef = useRef<Uniforms | null>(null);
112
+ const rendererRef = useRef<Renderer | null>(null);
113
+ const mouseRef = useRef({ x: 0.5, y: 0.5 });
114
+ const smoothMouseRef = useRef({ x: 0.5, y: 0.5 });
115
+ const animationIdRef = useRef<number | null>(null);
116
+ const meshRef = useRef<Mesh | null>(null);
117
+ const cleanupFunctionRef = useRef<(() => void) | null>(null);
118
+ const [isVisible, setIsVisible] = useState(false);
119
+ const observerRef = useRef<IntersectionObserver | null>(null);
120
+
121
+ useEffect(() => {
122
+ if (!containerRef.current) return;
123
+
124
+ observerRef.current = new IntersectionObserver(
125
+ entries => {
126
+ const entry = entries[0];
127
+ setIsVisible(entry.isIntersecting);
128
+ },
129
+ { threshold: 0.1 }
130
+ );
131
+
132
+ observerRef.current.observe(containerRef.current);
133
+
134
+ return () => {
135
+ if (observerRef.current) {
136
+ observerRef.current.disconnect();
137
+ observerRef.current = null;
138
+ }
139
+ };
140
+ }, []);
141
+
142
+ useEffect(() => {
143
+ if (!isVisible || !containerRef.current) return;
144
+
145
+ if (cleanupFunctionRef.current) {
146
+ cleanupFunctionRef.current();
147
+ cleanupFunctionRef.current = null;
148
+ }
149
+
150
+ const initializeWebGL = async () => {
151
+ if (!containerRef.current) return;
152
+
153
+ await new Promise(resolve => setTimeout(resolve, 10));
154
+
155
+ if (!containerRef.current) return;
156
+
157
+ const renderer = new Renderer({
158
+ dpr: Math.min(window.devicePixelRatio, 2),
159
+ alpha: true
160
+ });
161
+ rendererRef.current = renderer;
162
+
163
+ const gl = renderer.gl;
164
+ gl.canvas.style.width = '100%';
165
+ gl.canvas.style.height = '100%';
166
+
167
+ while (containerRef.current.firstChild) {
168
+ containerRef.current.removeChild(containerRef.current.firstChild);
169
+ }
170
+ containerRef.current.appendChild(gl.canvas);
171
+
172
+ const vert = `
173
+ attribute vec2 position;
174
+ varying vec2 vUv;
175
+ void main() {
176
+ vUv = position * 0.5 + 0.5;
177
+ gl_Position = vec4(position, 0.0, 1.0);
178
+ }`;
179
+
180
+ const frag = `precision highp float;
181
+
182
+ uniform float iTime;
183
+ uniform vec2 iResolution;
184
+
185
+ uniform vec2 rayPos;
186
+ uniform vec2 rayDir;
187
+ uniform vec3 raysColor;
188
+ uniform float raysSpeed;
189
+ uniform float lightSpread;
190
+ uniform float rayLength;
191
+ uniform float pulsating;
192
+ uniform float fadeDistance;
193
+ uniform float saturation;
194
+ uniform vec2 mousePos;
195
+ uniform float mouseInfluence;
196
+ uniform float noiseAmount;
197
+ uniform float distortion;
198
+
199
+ varying vec2 vUv;
200
+
201
+ float noise(vec2 st) {
202
+ return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
203
+ }
204
+
205
+ float rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord,
206
+ float seedA, float seedB, float speed) {
207
+ vec2 sourceToCoord = coord - raySource;
208
+ vec2 dirNorm = normalize(sourceToCoord);
209
+ float cosAngle = dot(dirNorm, rayRefDirection);
210
+
211
+ float distortedAngle = cosAngle + distortion * sin(iTime * 2.0 + length(sourceToCoord) * 0.01) * 0.2;
212
+
213
+ float spreadFactor = pow(max(distortedAngle, 0.0), 1.0 / max(lightSpread, 0.001));
214
+
215
+ float distance = length(sourceToCoord);
216
+ float maxDistance = iResolution.x * rayLength;
217
+ float lengthFalloff = clamp((maxDistance - distance) / maxDistance, 0.0, 1.0);
218
+
219
+ float fadeFalloff = clamp((iResolution.x * fadeDistance - distance) / (iResolution.x * fadeDistance), 0.5, 1.0);
220
+ float pulse = pulsating > 0.5 ? (0.8 + 0.2 * sin(iTime * speed * 3.0)) : 1.0;
221
+
222
+ float baseStrength = clamp(
223
+ (0.45 + 0.15 * sin(distortedAngle * seedA + iTime * speed)) +
224
+ (0.3 + 0.2 * cos(-distortedAngle * seedB + iTime * speed)),
225
+ 0.0, 1.0
226
+ );
227
+
228
+ return baseStrength * lengthFalloff * fadeFalloff * spreadFactor * pulse;
229
+ }
230
+
231
+ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
232
+ vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y);
233
+
234
+ vec2 finalRayDir = rayDir;
235
+ if (mouseInfluence > 0.0) {
236
+ vec2 mouseScreenPos = mousePos * iResolution.xy;
237
+ vec2 mouseDirection = normalize(mouseScreenPos - rayPos);
238
+ finalRayDir = normalize(mix(rayDir, mouseDirection, mouseInfluence));
239
+ }
240
+
241
+ vec4 rays1 = vec4(1.0) *
242
+ rayStrength(rayPos, finalRayDir, coord, 36.2214, 21.11349,
243
+ 1.5 * raysSpeed);
244
+ vec4 rays2 = vec4(1.0) *
245
+ rayStrength(rayPos, finalRayDir, coord, 22.3991, 18.0234,
246
+ 1.1 * raysSpeed);
247
+
248
+ fragColor = rays1 * 0.5 + rays2 * 0.4;
249
+
250
+ if (noiseAmount > 0.0) {
251
+ float n = noise(coord * 0.01 + iTime * 0.1);
252
+ fragColor.rgb *= (1.0 - noiseAmount + noiseAmount * n);
253
+ }
254
+
255
+ float brightness = 1.0 - (coord.y / iResolution.y);
256
+ fragColor.x *= 0.1 + brightness * 0.8;
257
+ fragColor.y *= 0.3 + brightness * 0.6;
258
+ fragColor.z *= 0.5 + brightness * 0.5;
259
+
260
+ if (saturation != 1.0) {
261
+ float gray = dot(fragColor.rgb, vec3(0.299, 0.587, 0.114));
262
+ fragColor.rgb = mix(vec3(gray), fragColor.rgb, saturation);
263
+ }
264
+
265
+ fragColor.rgb *= raysColor;
266
+ }
267
+
268
+ void main() {
269
+ vec4 color;
270
+ mainImage(color, gl_FragCoord.xy);
271
+ gl_FragColor = color;
272
+ }`;
273
+
274
+ const uniforms = {
275
+ iTime: { value: 0 },
276
+ iResolution: { value: [1, 1] },
277
+
278
+ rayPos: { value: [0, 0] },
279
+ rayDir: { value: [0, 1] },
280
+
281
+ raysColor: { value: hexToRgb(raysColor) },
282
+ raysSpeed: { value: raysSpeed },
283
+ lightSpread: { value: lightSpread },
284
+ rayLength: { value: rayLength },
285
+ pulsating: { value: pulsating ? 1.0 : 0.0 },
286
+ fadeDistance: { value: fadeDistance },
287
+ saturation: { value: saturation },
288
+ mousePos: { value: [0.5, 0.5] },
289
+ mouseInfluence: { value: mouseInfluence },
290
+ noiseAmount: { value: noiseAmount },
291
+ distortion: { value: distortion }
292
+ };
293
+ uniformsRef.current = uniforms;
294
+
295
+ const geometry = new Triangle(gl);
296
+ const program = new Program(gl, {
297
+ vertex: vert,
298
+ fragment: frag,
299
+ uniforms
300
+ });
301
+ const mesh = new Mesh(gl, { geometry, program });
302
+ meshRef.current = mesh;
303
+
304
+ const updatePlacement = () => {
305
+ if (!containerRef.current || !renderer) return;
306
+
307
+ renderer.dpr = Math.min(window.devicePixelRatio, 2);
308
+
309
+ const { clientWidth: wCSS, clientHeight: hCSS } = containerRef.current;
310
+ renderer.setSize(wCSS, hCSS);
311
+
312
+ const dpr = renderer.dpr;
313
+ const w = wCSS * dpr;
314
+ const h = hCSS * dpr;
315
+
316
+ uniforms.iResolution.value = [w, h];
317
+
318
+ const { anchor, dir } = getAnchorAndDir(raysOrigin, w, h);
319
+ uniforms.rayPos.value = anchor;
320
+ uniforms.rayDir.value = dir;
321
+ };
322
+
323
+ const loop = (t: number) => {
324
+ if (!rendererRef.current || !uniformsRef.current || !meshRef.current) {
325
+ return;
326
+ }
327
+
328
+ uniforms.iTime.value = t * 0.001;
329
+
330
+ if (followMouse && mouseInfluence > 0.0) {
331
+ const smoothing = 0.92;
332
+
333
+ smoothMouseRef.current.x =
334
+ smoothMouseRef.current.x * smoothing +
335
+ mouseRef.current.x * (1 - smoothing);
336
+ smoothMouseRef.current.y =
337
+ smoothMouseRef.current.y * smoothing +
338
+ mouseRef.current.y * (1 - smoothing);
339
+
340
+ uniforms.mousePos.value = [
341
+ smoothMouseRef.current.x,
342
+ smoothMouseRef.current.y
343
+ ];
344
+ }
345
+
346
+ try {
347
+ renderer.render({ scene: mesh });
348
+ animationIdRef.current = requestAnimationFrame(loop);
349
+ } catch (error) {
350
+ console.warn('WebGL rendering error:', error);
351
+ return;
352
+ }
353
+ };
354
+
355
+ window.addEventListener('resize', updatePlacement);
356
+ updatePlacement();
357
+ animationIdRef.current = requestAnimationFrame(loop);
358
+
359
+ cleanupFunctionRef.current = () => {
360
+ if (animationIdRef.current) {
361
+ cancelAnimationFrame(animationIdRef.current);
362
+ animationIdRef.current = null;
363
+ }
364
+
365
+ window.removeEventListener('resize', updatePlacement);
366
+
367
+ if (renderer) {
368
+ try {
369
+ const canvas = renderer.gl.canvas;
370
+ const loseContextExt =
371
+ renderer.gl.getExtension('WEBGL_lose_context');
372
+ if (loseContextExt) {
373
+ loseContextExt.loseContext();
374
+ }
375
+
376
+ if (canvas && canvas.parentNode) {
377
+ canvas.parentNode.removeChild(canvas);
378
+ }
379
+ } catch (error) {
380
+ console.warn('Error during WebGL cleanup:', error);
381
+ }
382
+ }
383
+
384
+ rendererRef.current = null;
385
+ uniformsRef.current = null;
386
+ meshRef.current = null;
387
+ };
388
+ };
389
+
390
+ initializeWebGL();
391
+
392
+ return () => {
393
+ if (cleanupFunctionRef.current) {
394
+ cleanupFunctionRef.current();
395
+ cleanupFunctionRef.current = null;
396
+ }
397
+ };
398
+ }, [
399
+ isVisible,
400
+ raysOrigin,
401
+ raysColor,
402
+ raysSpeed,
403
+ lightSpread,
404
+ rayLength,
405
+ pulsating,
406
+ fadeDistance,
407
+ saturation,
408
+ followMouse,
409
+ mouseInfluence,
410
+ noiseAmount,
411
+ distortion
412
+ ]);
413
+
414
+ useEffect(() => {
415
+ if (!uniformsRef.current || !containerRef.current || !rendererRef.current)
416
+ return;
417
+
418
+ const u = uniformsRef.current;
419
+ const renderer = rendererRef.current;
420
+
421
+ u.raysColor.value = hexToRgb(raysColor);
422
+ u.raysSpeed.value = raysSpeed;
423
+ u.lightSpread.value = lightSpread;
424
+ u.rayLength.value = rayLength;
425
+ u.pulsating.value = pulsating ? 1.0 : 0.0;
426
+ u.fadeDistance.value = fadeDistance;
427
+ u.saturation.value = saturation;
428
+ u.mouseInfluence.value = mouseInfluence;
429
+ u.noiseAmount.value = noiseAmount;
430
+ u.distortion.value = distortion;
431
+
432
+ const { clientWidth: wCSS, clientHeight: hCSS } = containerRef.current;
433
+ const dpr = renderer.dpr;
434
+ const { anchor, dir } = getAnchorAndDir(raysOrigin, wCSS * dpr, hCSS * dpr);
435
+ u.rayPos.value = anchor;
436
+ u.rayDir.value = dir;
437
+ }, [
438
+ raysColor,
439
+ raysSpeed,
440
+ lightSpread,
441
+ raysOrigin,
442
+ rayLength,
443
+ pulsating,
444
+ fadeDistance,
445
+ saturation,
446
+ mouseInfluence,
447
+ noiseAmount,
448
+ distortion
449
+ ]);
450
+
451
+ useEffect(() => {
452
+ const handleMouseMove = (e: MouseEvent) => {
453
+ if (!containerRef.current || !rendererRef.current) return;
454
+ const rect = containerRef.current.getBoundingClientRect();
455
+ const x = (e.clientX - rect.left) / rect.width;
456
+ const y = (e.clientY - rect.top) / rect.height;
457
+ mouseRef.current = { x, y };
458
+ };
459
+
460
+ if (followMouse) {
461
+ window.addEventListener('mousemove', handleMouseMove);
462
+ return () => window.removeEventListener('mousemove', handleMouseMove);
463
+ }
464
+ }, [followMouse]);
465
+
466
+ return (
467
+ <div
468
+ ref={containerRef}
469
+ className={`w-full h-full pointer-events-none z-[3] overflow-hidden relative ${className}`.trim()}
470
+ />
471
+ );
472
+ };
473
+
474
+ export default LightRays;
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { ThemeProvider as NextThemesProvider } from 'next-themes';
5
+
6
+ export function ThemeProvider({
7
+ children,
8
+ ...props
9
+ }: React.ComponentProps<typeof NextThemesProvider>) {
10
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
11
+ }
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '@/lib/utils';
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<'div'>) {
6
+ return (
7
+ <div
8
+ data-slot="card"
9
+ className={cn(
10
+ 'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ );
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn('leading-none font-semibold', className)}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn('text-muted-foreground text-sm', className)}
46
+ {...props}
47
+ />
48
+ );
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
57
+ className
58
+ )}
59
+ {...props}
60
+ />
61
+ );
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn('px-6', className)}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
79
+ {...props}
80
+ />
81
+ );
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent
92
+ };