zeroed-some/bashamole / 4cba9cf

Browse files

keep satisfying the linter

Authored by espadonne
SHA
4cba9cff52b1168a6e39f4e3c461ac8c024d1ad7
Parents
f72c663
Tree
e797ef5

2 changed files

StatusFile+-
M frontend/src/components/Game.tsx 5 1
M frontend/src/components/TreeVisualizer.tsx 101 96
frontend/src/components/Game.tsxmodified
@@ -1,6 +1,7 @@
11
 "use client";
22
 
33
 import React, { useState, useEffect, useRef } from 'react';
4
+import Image from 'next/image';
45
 import TreeVisualizer from './TreeVisualizer';
56
 import { gameApi, FileSystemTree, FHSDirectory, CommandReferenceResponse, MoleDirection, TreeNode } from '@/lib/api';
67
 
@@ -300,6 +301,7 @@ const Game: React.FC = () => {
300301
   // Start game on mount
301302
   useEffect(() => {
302303
     startNewGame();
304
+  // eslint-disable-next-line react-hooks/exhaustive-deps
303305
   }, []);
304306
 
305307
   // Mark intro as played after first render
@@ -417,9 +419,11 @@ const Game: React.FC = () => {
417419
           }}
418420
         >
419421
           <div className="bg-red-600/90 backdrop-blur-sm border-2 border-red-400 rounded-lg p-3 shadow-2xl flex items-center gap-2">
420
-            <img 
422
+            <Image 
421423
               src="/mole.svg" 
422424
               alt="Mole" 
425
+              width={32}
426
+              height={32}
423427
               className="w-8 h-8"
424428
             />
425429
             <div 
frontend/src/components/TreeVisualizer.tsxmodified
@@ -5,6 +5,90 @@ import React, { useEffect, useRef } from 'react';
55
 import * as d3 from 'd3';
66
 import { TreeNode } from '@/lib/api';
77
 
8
+// Quirky visual configuration - moved outside component to avoid dependency issues
9
+const NODE_CONFIG = {
10
+  sizes: {
11
+    root: { base: 30, hover: 35 },
12
+    player: { base: 26, hover: 28 },
13
+    regular: { base: 20, hover: 24 },
14
+    mole: { base: 22, hover: 26 }
15
+  },
16
+  colors: {
17
+    player: { 
18
+      fill: '#60A5FA', 
19
+      stroke: '#3B82F6',
20
+      glow: '#93C5FD'
21
+    },
22
+    mole: { 
23
+      fill: '#F87171', 
24
+      stroke: '#DC2626',
25
+      pulse: '#FCA5A5'
26
+    },
27
+    fhs: { 
28
+      fill: '#C084FC', 
29
+      stroke: '#9333EA',
30
+      pattern: 'fhs-pattern'
31
+    },
32
+    regular: { 
33
+      fill: '#86EFAC', 
34
+      stroke: '#22C55E',
35
+      hover: '#BBF7D0'
36
+    },
37
+    root: {
38
+      fill: '#FDE047',
39
+      stroke: '#EAB308'
40
+    }
41
+  },
42
+  strokeWidth: { base: 3, hover: 4 },
43
+  wobble: {
44
+    amount: 2,
45
+    speed: 3000
46
+  }
47
+};
48
+
49
+const ICON_CONFIG = {
50
+  size: 40,
51
+  offset: -20,
52
+  paths: {
53
+    player: '/player.svg',
54
+    mole: '/mole.svg'
55
+  }
56
+};
57
+
58
+const ANIMATION_CONFIG = {
59
+  nodeHover: { duration: 300 },
60
+  navigation: { duration: 750, easing: d3.easeCubicInOut },
61
+  intro: {
62
+    phases: [
63
+      { duration: 1000 },
64
+      { duration: 2000, easing: d3.easeCubicInOut },
65
+      { duration: 1000 },
66
+      { duration: 1500, easing: d3.easeCubicInOut },
67
+      { duration: 800 },
68
+      { duration: 1200, easing: d3.easeCubicInOut },
69
+      { duration: 1500, easing: d3.easeCubicInOut }
70
+    ]
71
+  },
72
+  celebration: { duration: '1s', repeatCount: 'indefinite' },
73
+  pulse: { duration: '2s', repeatCount: 'indefinite' }
74
+};
75
+
76
+const PARTICLE_CONFIG = {
77
+  count: 30,
78
+  size: { min: 2, max: 6 },
79
+  colors: ['#FDE047', '#A78BFA', '#F87171', '#60A5FA', '#86EFAC'],
80
+  speed: { min: 20000, max: 40000 }
81
+};
82
+
83
+const ZOOM_CONFIG = {
84
+  scaleExtent: [0.1, 3] as [number, number],
85
+  defaultScale: 2.5,
86
+  fullTreeScale: 0.8,
87
+  partialTreeScale: 1.5,
88
+  treePadding: 200,
89
+  nudgeOffset: { x: 0.15, y: 0.2 }
90
+};
91
+
892
 interface TreeVisualizerProps {
993
   treeData: TreeNode;
1094
   playerLocation: string;
@@ -26,74 +110,6 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
26110
   const containerRef = useRef<HTMLDivElement>(null);
27111
   const previousLocationRef = useRef<string | null>(null);
28112
 
29
-  // Quirky visual configuration
30
-  const NODE_CONFIG = {
31
-    sizes: {
32
-      root: { base: 30, hover: 35 },
33
-      player: { base: 26, hover: 28 },
34
-      regular: { base: 20, hover: 24 },
35
-      mole: { base: 22, hover: 26 }
36
-    },
37
-    colors: {
38
-      player: { 
39
-        fill: '#60A5FA', 
40
-        stroke: '#3B82F6',
41
-        glow: '#93C5FD'
42
-      },
43
-      mole: { 
44
-        fill: '#F87171', 
45
-        stroke: '#DC2626',
46
-        pulse: '#FCA5A5'
47
-      },
48
-      fhs: { 
49
-        fill: '#C084FC', 
50
-        stroke: '#9333EA',
51
-        pattern: 'fhs-pattern'
52
-      },
53
-      regular: { 
54
-        fill: '#86EFAC', 
55
-        stroke: '#22C55E',
56
-        hover: '#BBF7D0'
57
-      },
58
-      root: {
59
-        fill: '#FDE047',
60
-        stroke: '#EAB308'
61
-      }
62
-    },
63
-    strokeWidth: { base: 3, hover: 4 },
64
-    wobble: {
65
-      amount: 2,
66
-      speed: 3000
67
-    }
68
-  };
69
-
70
-  const ICON_CONFIG = {
71
-    size: 40,
72
-    offset: -20,
73
-    paths: {
74
-      player: '/player.svg',
75
-      mole: '/mole.svg'
76
-    }
77
-  };
78
-
79
-  const ANIMATION_CONFIG = {
80
-    nodeHover: { duration: 300 },
81
-    navigation: { duration: 750, easing: d3.easeCubicInOut },
82
-    intro: {
83
-      phases: [
84
-        { duration: 1000 },
85
-        { duration: 2000, easing: d3.easeCubicInOut },
86
-        { duration: 1000 },
87
-        { duration: 1500, easing: d3.easeCubicInOut },
88
-        { duration: 800 },
89
-        { duration: 1200, easing: d3.easeCubicInOut },
90
-        { duration: 1500, easing: d3.easeCubicInOut }
91
-      ]
92
-    },
93
-    celebration: { duration: '1s', repeatCount: 'indefinite' },
94
-    pulse: { duration: '2s', repeatCount: 'indefinite' }
95
-  };
96
-
97113
   const LAYOUT_CONFIG = {
98114
     nodeSpacing: 140,
99115
     margin: { top: 120, right: 160, bottom: 120, left: 160 },
@@ -105,15 +121,6 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
105121
     }
106122
   };
107123
 
108
-  const ZOOM_CONFIG = {
109
-    scaleExtent: [0.1, 3] as [number, number],
110
-    defaultScale: 2.5,
111
-    fullTreeScale: 0.8,
112
-    partialTreeScale: 1.5,
113
-    treePadding: 200,
114
-    nudgeOffset: { x: 0.15, y: 0.2 }
115
-  };
116
-
117124
   const LINK_CONFIG = {
118125
     strokeWidth: 3,
119126
     opacity: 0.6,
@@ -141,13 +148,6 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
141148
     }
142149
   };
143150
 
144
-  const PARTICLE_CONFIG = {
145
-    count: 30,
146
-    size: { min: 2, max: 6 },
147
-    colors: ['#FDE047', '#A78BFA', '#F87171', '#60A5FA', '#86EFAC'],
148
-    speed: { min: 20000, max: 40000 }
149
-  };
150
-
151151
   const isAnimatingRef = useRef(false);
152152
 
153153
   useEffect(() => {
@@ -170,7 +170,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
170170
     const root = d3.hierarchy(treeData);
171171
     
172172
     const levelCounts: { [key: number]: number } = {};
173
-    root.each(d => {
173
+    root.each((d) => {
174174
       levelCounts[d.depth] = (levelCounts[d.depth] || 0) + 1;
175175
     });
176176
     const maxNodesAtLevel = Math.max(...Object.values(levelCounts));
@@ -284,7 +284,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
284284
       .size([width - margin.left - margin.right, height - margin.top - margin.bottom])
285285
       .separation((a, b) => {
286286
         const aParentChildCount = a.parent ? (a.parent.children?.length || 0) : 0;
287
-        const bParentChildCount = b.parent ? (b.parent.children?.length || 0) : 0;
287
+        // const bParentChildCount = b.parent ? (b.parent.children?.length || 0) : 0;
288288
         
289289
         if (a.parent === b.parent && aParentChildCount > 3) {
290290
           const aIsLeaf = !a.children || a.children.length === 0;
@@ -313,8 +313,8 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
313313
     
314314
     // Center the root
315315
     const rootX = width / 2;
316
-    treeNodes.each(d => {
317
-      d.x = d.x + (rootX - root.x);
316
+    treeNodes.each((d) => {
317
+      d.x = d.x + (rootX - treeNodes.x);
318318
     });
319319
 
320320
     // Helper function to check if a node is adjacent
@@ -357,7 +357,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
357357
       .attr('d', linkGenerator)
358358
       .style('fill', 'none')
359359
       .style('stroke', d => {
360
-        const targetPath = (d.target as any).data.path;
360
+        const targetPath = (d.target as d3.HierarchyPointNode<TreeNode>).data.path;
361361
         if (isAdjacentNode(targetPath, playerLocation) || targetPath === playerLocation) {
362362
           return LINK_CONFIG.colors.adjacent;
363363
         }
@@ -365,7 +365,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
365365
       })
366366
       .style('stroke-width', LINK_CONFIG.strokeWidth)
367367
       .style('stroke-dasharray', d => {
368
-        const targetPath = (d.target as any).data.path;
368
+        const targetPath = (d.target as d3.HierarchyPointNode<TreeNode>).data.path;
369369
         if (targetPath === playerLocation) return 'none';
370370
         return LINK_CONFIG.dashArray;
371371
       })
@@ -493,15 +493,18 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
493493
 
494494
     // Add interactivity
495495
     node.selectAll('.node-shape')
496
-      .style('cursor', d => {
496
+      .style('cursor', function(this: any) {
497
+        const d = d3.select(this.parentNode).datum() as d3.HierarchyPointNode<TreeNode>;
497498
         if (d.data.path === playerLocation) return 'default';
498499
         return isAdjacentNode(d.data.path, playerLocation) ? 'pointer' : 'not-allowed';
499500
       })
500
-      .style('opacity', d => {
501
+      .style('opacity', function(this: any) {
502
+        const d = d3.select(this.parentNode).datum() as d3.HierarchyPointNode<TreeNode>;
501503
         if (d.data.path === playerLocation) return 1;
502504
         return isAdjacentNode(d.data.path, playerLocation) ? 1 : 0.5;
503505
       })
504
-      .on('mouseover', function(event, d) {
506
+      .on('mouseover', function(this: any, event: MouseEvent) {
507
+        const d = d3.select(this.parentNode).datum() as d3.HierarchyPointNode<TreeNode>;
505508
         if (d.data.path !== playerLocation && isAdjacentNode(d.data.path, playerLocation)) {
506509
           d3.select(this)
507510
             .transition()
@@ -513,7 +516,8 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
513516
             .style('filter', 'url(#glow) drop-shadow(0 0 8px rgba(0,0,0,0.4))');
514517
         }
515518
       })
516
-      .on('mouseout', function(event, d) {
519
+      .on('mouseout', function(this: any, event: MouseEvent) {
520
+        const d = d3.select(this.parentNode).datum() as d3.HierarchyPointNode<TreeNode>;
517521
         d3.select(this)
518522
           .transition()
519523
           .duration(ANIMATION_CONFIG.nodeHover.duration)
@@ -525,7 +529,8 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
525529
           })
526530
           .style('filter', d.data.path === playerLocation ? 'url(#glow)' : 'url(#drop-shadow)');
527531
       })
528
-      .on('click', (event, d) => {
532
+      .on('click', function(this: any, event: MouseEvent) {
533
+        const d = d3.select(this.parentNode).datum() as d3.HierarchyPointNode<TreeNode>;
529534
         if (onNodeClick && d.data.path !== playerLocation && isAdjacentNode(d.data.path, playerLocation)) {
530535
           onNodeClick(d.data.path);
531536
         }
@@ -808,7 +813,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
808813
         svg.call(zoom.transform, playerTransform);
809814
       }
810815
     }
811
-
816
+  // eslint-disable-next-line react-hooks/exhaustive-deps
812817
   }, [treeData, playerLocation, onNodeClick, playIntro, isDarkMode, moleKilled]);
813818
 
814819
   return (