|
1 | 1 | <script lang="ts"> |
2 | 2 | /** Props for the grid size */ |
3 | 3 | let { size = 40 }: { size?: number } = $props(); |
4 | | -
|
5 | 4 | /** State for the number of columns and rows in the grid */ |
6 | 5 | let columns = $state(0); |
7 | | -
|
8 | 6 | /** State for the number of rows in the grid */ |
9 | 7 | let rows = $state(0); |
10 | | -
|
11 | 8 | /** State for the currently hovered cell */ |
12 | 9 | let hoveredCell = $state<{ x: number; y: number } | null>(null); |
13 | | -
|
14 | 10 | /** Reference to the grid container */ |
15 | 11 | let container: HTMLElement; |
16 | | -
|
17 | 12 | /** Derived state for the row indices */ |
18 | 13 | let rowIndices = $derived(Array.from({ length: rows }, (_, i) => i)); |
19 | | -
|
20 | 14 | /** Derived state for the column indices */ |
21 | 15 | let colIndices = $derived(Array.from({ length: columns }, (_, i) => i)); |
22 | 16 |
|
23 | 17 | $effect(() => { |
24 | 18 | if (!container) return; |
25 | | -
|
26 | 19 | const updateSize = () => { |
27 | 20 | columns = Math.ceil(container.clientWidth / size); |
28 | 21 | rows = Math.ceil(container.clientHeight / size); |
29 | 22 | }; |
30 | | -
|
31 | 23 | const handleMouseMove = (e: MouseEvent) => { |
32 | 24 | if (!container) return; |
33 | | -
|
34 | 25 | const rect = container.getBoundingClientRect(); |
35 | | -
|
36 | 26 | if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) { |
37 | 27 | hoveredCell = null; |
38 | 28 | return; |
39 | 29 | } |
40 | | -
|
41 | 30 | const cellX = Math.floor((e.clientX - rect.left) / size); |
42 | 31 | const cellY = Math.floor((e.clientY - rect.top) / size); |
43 | | -
|
44 | 32 | if (hoveredCell?.x === cellX && hoveredCell?.y === cellY) return; |
45 | | -
|
46 | 33 | hoveredCell = { x: cellX, y: cellY }; |
47 | 34 | }; |
48 | | -
|
49 | 35 | updateSize(); |
50 | 36 | window.addEventListener("resize", updateSize); |
51 | 37 | window.addEventListener("mousemove", handleMouseMove); |
52 | | -
|
53 | 38 | return () => { |
54 | 39 | window.removeEventListener("resize", updateSize); |
55 | 40 | window.removeEventListener("mousemove", handleMouseMove); |
56 | 41 | }; |
57 | 42 | }); |
58 | 43 | </script> |
59 | 44 |
|
60 | | -<figure |
61 | | - bind:this={container} |
62 | | - aria-hidden="true" |
63 | | - class="pointer-events-none absolute inset-0 z-0 overflow-hidden mask-[linear-gradient(to_bottom,transparent_0%,black_10%,black_90%,transparent_100%)]" |
64 | | - style="display: grid; grid-template-columns: repeat({columns}, {size}px); grid-template-rows: repeat({rows}, {size}px);" |
65 | | -> |
66 | | - {#each rowIndices as r (r)} |
67 | | - {#each colIndices as c (c)} |
68 | | - {@const isHovered = hoveredCell && Math.abs(hoveredCell.x - c) <= 1 && Math.abs(hoveredCell.y - r) <= 1} |
69 | | - <div |
70 | | - class="border-r border-b border-neutral-200/60 transition-colors {isHovered |
71 | | - ? 'bg-neutral-800/15 duration-75' |
72 | | - : 'bg-transparent duration-500'}" |
73 | | - ></div> |
| 45 | +<div bind:this={container} class="pointer-events-none absolute inset-0 z-0 overflow-hidden bg-blue-600"> |
| 46 | + <div |
| 47 | + class="absolute inset-0" |
| 48 | + style="background-image: |
| 49 | + radial-gradient(ellipse 75% 65% at 50% 0%, white 0%, white 70%, rgb(255 255 255 / 0) 80%), |
| 50 | + radial-gradient(ellipse 75% 65% at 50% 100%, white 0%, white 70%, rgb(255 255 255 / 0) 80%);" |
| 51 | + ></div> |
| 52 | + |
| 53 | + <figure |
| 54 | + aria-hidden="true" |
| 55 | + class="pointer-events-none absolute inset-0 z-0 overflow-hidden mask-[linear-gradient(to_bottom,transparent_0%,black_10%,black_90%,transparent_100%)]" |
| 56 | + style="display: grid; grid-template-columns: repeat({columns}, {size}px); grid-template-rows: repeat({rows}, {size}px);" |
| 57 | + > |
| 58 | + {#each rowIndices as r (r)} |
| 59 | + {#each colIndices as c (c)} |
| 60 | + {@const isHovered = hoveredCell && Math.abs(hoveredCell.x - c) <= 1 && Math.abs(hoveredCell.y - r) <= 1} |
| 61 | + <div |
| 62 | + class="border-r border-b border-white/20 transition-colors {isHovered |
| 63 | + ? 'bg-white/15 duration-75' |
| 64 | + : 'bg-transparent duration-500'}" |
| 65 | + ></div> |
| 66 | + {/each} |
74 | 67 | {/each} |
75 | | - {/each} |
76 | | -</figure> |
| 68 | + </figure> |
| 69 | +</div> |
0 commit comments