Add stuff
This commit is contained in:
		@@ -29,6 +29,8 @@
 | 
				
			|||||||
    "postgres": "^3.4.4",
 | 
					    "postgres": "^3.4.4",
 | 
				
			||||||
    "react": "^18.3.1",
 | 
					    "react": "^18.3.1",
 | 
				
			||||||
    "react-dom": "^18.3.1",
 | 
					    "react-dom": "^18.3.1",
 | 
				
			||||||
 | 
					    "react-icons": "^5.3.0",
 | 
				
			||||||
 | 
					    "recharts": "^2.12.7",
 | 
				
			||||||
    "tailwind-merge": "^2.5.2",
 | 
					    "tailwind-merge": "^2.5.2",
 | 
				
			||||||
    "tailwindcss-animate": "^1.0.7",
 | 
					    "tailwindcss-animate": "^1.0.7",
 | 
				
			||||||
    "zod": "^3.23.3"
 | 
					    "zod": "^3.23.3"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										277
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										277
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@@ -53,6 +53,12 @@ importers:
 | 
				
			|||||||
      react-dom:
 | 
					      react-dom:
 | 
				
			||||||
        specifier: ^18.3.1
 | 
					        specifier: ^18.3.1
 | 
				
			||||||
        version: 18.3.1(react@18.3.1)
 | 
					        version: 18.3.1(react@18.3.1)
 | 
				
			||||||
 | 
					      react-icons:
 | 
				
			||||||
 | 
					        specifier: ^5.3.0
 | 
				
			||||||
 | 
					        version: 5.3.0(react@18.3.1)
 | 
				
			||||||
 | 
					      recharts:
 | 
				
			||||||
 | 
					        specifier: ^2.12.7
 | 
				
			||||||
 | 
					        version: 2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
 | 
				
			||||||
      tailwind-merge:
 | 
					      tailwind-merge:
 | 
				
			||||||
        specifier: ^2.5.2
 | 
					        specifier: ^2.5.2
 | 
				
			||||||
        version: 2.5.2
 | 
					        version: 2.5.2
 | 
				
			||||||
@@ -115,6 +121,10 @@ packages:
 | 
				
			|||||||
    resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
 | 
					    resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
 | 
				
			||||||
    engines: {node: '>=10'}
 | 
					    engines: {node: '>=10'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/runtime@7.25.6':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.9.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  '@drizzle-team/brocli@0.10.1':
 | 
					  '@drizzle-team/brocli@0.10.1':
 | 
				
			||||||
    resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==}
 | 
					    resolution: {integrity: sha512-AHy0vjc+n/4w/8Mif+w86qpppHuF3AyXbcWW+R/W7GNA3F5/p2nuhlkCJaTXSLZheB4l1rtHzOfr9A7NwoR/Zg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -860,6 +870,33 @@ packages:
 | 
				
			|||||||
      typescript:
 | 
					      typescript:
 | 
				
			||||||
        optional: true
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-array@3.2.1':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-color@3.1.3':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-ease@3.0.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-interpolate@3.0.4':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-path@3.1.0':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-scale@4.0.8':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-shape@3.1.6':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-time@3.0.3':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-timer@3.0.2':
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  '@types/eslint@8.56.12':
 | 
					  '@types/eslint@8.56.12':
 | 
				
			||||||
    resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==}
 | 
					    resolution: {integrity: sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1192,6 +1229,50 @@ packages:
 | 
				
			|||||||
  csstype@3.1.3:
 | 
					  csstype@3.1.3:
 | 
				
			||||||
    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 | 
					    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-array@3.2.4:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-color@3.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-ease@3.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-format@3.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-interpolate@3.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-path@3.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-scale@4.0.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-shape@3.2.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-time-format@4.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-time@3.1.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-timer@3.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  damerau-levenshtein@1.0.8:
 | 
					  damerau-levenshtein@1.0.8:
 | 
				
			||||||
    resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
 | 
					    resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1224,6 +1305,9 @@ packages:
 | 
				
			|||||||
      supports-color:
 | 
					      supports-color:
 | 
				
			||||||
        optional: true
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  decimal.js-light@2.5.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deep-equal@2.2.3:
 | 
					  deep-equal@2.2.3:
 | 
				
			||||||
    resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
 | 
					    resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
 | 
				
			||||||
    engines: {node: '>= 0.4'}
 | 
					    engines: {node: '>= 0.4'}
 | 
				
			||||||
@@ -1260,6 +1344,9 @@ packages:
 | 
				
			|||||||
    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
 | 
					    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
 | 
				
			||||||
    engines: {node: '>=6.0.0'}
 | 
					    engines: {node: '>=6.0.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dom-helpers@5.2.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  drizzle-kit@0.24.2:
 | 
					  drizzle-kit@0.24.2:
 | 
				
			||||||
    resolution: {integrity: sha512-nXOaTSFiuIaTMhS8WJC2d4EBeIcN9OSt2A2cyFbQYBAZbi7lRsVGJNqDpEwPqYfJz38yxbY/UtbvBBahBfnExQ==}
 | 
					    resolution: {integrity: sha512-nXOaTSFiuIaTMhS8WJC2d4EBeIcN9OSt2A2cyFbQYBAZbi7lRsVGJNqDpEwPqYfJz38yxbY/UtbvBBahBfnExQ==}
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
@@ -1531,9 +1618,16 @@ packages:
 | 
				
			|||||||
    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
 | 
					    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
 | 
				
			||||||
    engines: {node: '>=0.10.0'}
 | 
					    engines: {node: '>=0.10.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  eventemitter3@4.0.7:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fast-deep-equal@3.1.3:
 | 
					  fast-deep-equal@3.1.3:
 | 
				
			||||||
    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
 | 
					    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fast-equals@5.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=6.0.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fast-glob@3.3.2:
 | 
					  fast-glob@3.3.2:
 | 
				
			||||||
    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
 | 
					    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
 | 
				
			||||||
    engines: {node: '>=8.6.0'}
 | 
					    engines: {node: '>=8.6.0'}
 | 
				
			||||||
@@ -1702,6 +1796,10 @@ packages:
 | 
				
			|||||||
    resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
 | 
					    resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
 | 
				
			||||||
    engines: {node: '>= 0.4'}
 | 
					    engines: {node: '>= 0.4'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  internmap@2.0.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
 | 
				
			||||||
 | 
					    engines: {node: '>=12'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  invariant@2.2.4:
 | 
					  invariant@2.2.4:
 | 
				
			||||||
    resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
 | 
					    resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1897,6 +1995,9 @@ packages:
 | 
				
			|||||||
  lodash.merge@4.6.2:
 | 
					  lodash.merge@4.6.2:
 | 
				
			||||||
    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
 | 
					    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lodash@4.17.21:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loose-envify@1.4.0:
 | 
					  loose-envify@1.4.0:
 | 
				
			||||||
    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
 | 
					    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
@@ -2209,6 +2310,11 @@ packages:
 | 
				
			|||||||
    peerDependencies:
 | 
					    peerDependencies:
 | 
				
			||||||
      react: ^18.3.1
 | 
					      react: ^18.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-icons@5.3.0:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      react: '*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react-is@16.13.1:
 | 
					  react-is@16.13.1:
 | 
				
			||||||
    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
 | 
					    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2232,6 +2338,12 @@ packages:
 | 
				
			|||||||
      '@types/react':
 | 
					      '@types/react':
 | 
				
			||||||
        optional: true
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-smooth@4.0.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      react: ^16.8.0 || ^17.0.0 || ^18.0.0
 | 
				
			||||||
 | 
					      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react-style-singleton@2.2.1:
 | 
					  react-style-singleton@2.2.1:
 | 
				
			||||||
    resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
 | 
					    resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
 | 
				
			||||||
    engines: {node: '>=10'}
 | 
					    engines: {node: '>=10'}
 | 
				
			||||||
@@ -2242,6 +2354,12 @@ packages:
 | 
				
			|||||||
      '@types/react':
 | 
					      '@types/react':
 | 
				
			||||||
        optional: true
 | 
					        optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-transition-group@4.4.5:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      react: '>=16.6.0'
 | 
				
			||||||
 | 
					      react-dom: '>=16.6.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react@18.3.1:
 | 
					  react@18.3.1:
 | 
				
			||||||
    resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
 | 
					    resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
 | 
				
			||||||
    engines: {node: '>=0.10.0'}
 | 
					    engines: {node: '>=0.10.0'}
 | 
				
			||||||
@@ -2253,10 +2371,23 @@ packages:
 | 
				
			|||||||
    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
 | 
					    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
 | 
				
			||||||
    engines: {node: '>=8.10.0'}
 | 
					    engines: {node: '>=8.10.0'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recharts-scale@0.4.5:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recharts@2.12.7:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==}
 | 
				
			||||||
 | 
					    engines: {node: '>=14'}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      react: ^16.0.0 || ^17.0.0 || ^18.0.0
 | 
				
			||||||
 | 
					      react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reflect.getprototypeof@1.0.6:
 | 
					  reflect.getprototypeof@1.0.6:
 | 
				
			||||||
    resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
 | 
					    resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
 | 
				
			||||||
    engines: {node: '>= 0.4'}
 | 
					    engines: {node: '>= 0.4'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  regenerator-runtime@0.14.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  regexp.prototype.flags@1.5.2:
 | 
					  regexp.prototype.flags@1.5.2:
 | 
				
			||||||
    resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
 | 
					    resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
 | 
				
			||||||
    engines: {node: '>= 0.4'}
 | 
					    engines: {node: '>= 0.4'}
 | 
				
			||||||
@@ -2453,6 +2584,9 @@ packages:
 | 
				
			|||||||
  thenify@3.3.1:
 | 
					  thenify@3.3.1:
 | 
				
			||||||
    resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
 | 
					    resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tiny-invariant@1.3.3:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  to-regex-range@5.0.1:
 | 
					  to-regex-range@5.0.1:
 | 
				
			||||||
    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
 | 
					    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
 | 
				
			||||||
    engines: {node: '>=8.0'}
 | 
					    engines: {node: '>=8.0'}
 | 
				
			||||||
@@ -2533,6 +2667,9 @@ packages:
 | 
				
			|||||||
  util-deprecate@1.0.2:
 | 
					  util-deprecate@1.0.2:
 | 
				
			||||||
    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 | 
					    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  victory-vendor@36.9.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  which-boxed-primitive@1.0.2:
 | 
					  which-boxed-primitive@1.0.2:
 | 
				
			||||||
    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
 | 
					    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2584,6 +2721,10 @@ snapshots:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  '@alloc/quick-lru@5.2.0': {}
 | 
					  '@alloc/quick-lru@5.2.0': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@babel/runtime@7.25.6':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      regenerator-runtime: 0.14.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  '@drizzle-team/brocli@0.10.1': {}
 | 
					  '@drizzle-team/brocli@0.10.1': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  '@esbuild-kit/core-utils@3.3.2':
 | 
					  '@esbuild-kit/core-utils@3.3.2':
 | 
				
			||||||
@@ -3152,6 +3293,30 @@ snapshots:
 | 
				
			|||||||
    optionalDependencies:
 | 
					    optionalDependencies:
 | 
				
			||||||
      typescript: 5.6.2
 | 
					      typescript: 5.6.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-array@3.2.1': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-color@3.1.3': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-ease@3.0.2': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-interpolate@3.0.4':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@types/d3-color': 3.1.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-path@3.1.0': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-scale@4.0.8':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@types/d3-time': 3.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-shape@3.1.6':
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@types/d3-path': 3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-time@3.0.3': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  '@types/d3-timer@3.0.2': {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  '@types/eslint@8.56.12':
 | 
					  '@types/eslint@8.56.12':
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      '@types/estree': 1.0.5
 | 
					      '@types/estree': 1.0.5
 | 
				
			||||||
@@ -3552,6 +3717,44 @@ snapshots:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  csstype@3.1.3: {}
 | 
					  csstype@3.1.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-array@3.2.4:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      internmap: 2.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-color@3.1.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-ease@3.0.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-format@3.1.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-interpolate@3.0.1:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      d3-color: 3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-path@3.1.0: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-scale@4.0.2:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      d3-array: 3.2.4
 | 
				
			||||||
 | 
					      d3-format: 3.1.0
 | 
				
			||||||
 | 
					      d3-interpolate: 3.0.1
 | 
				
			||||||
 | 
					      d3-time: 3.1.0
 | 
				
			||||||
 | 
					      d3-time-format: 4.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-shape@3.2.0:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      d3-path: 3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-time-format@4.1.0:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      d3-time: 3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-time@3.1.0:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      d3-array: 3.2.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  d3-timer@3.0.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  damerau-levenshtein@1.0.8: {}
 | 
					  damerau-levenshtein@1.0.8: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  data-view-buffer@1.0.1:
 | 
					  data-view-buffer@1.0.1:
 | 
				
			||||||
@@ -3580,6 +3783,8 @@ snapshots:
 | 
				
			|||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      ms: 2.1.3
 | 
					      ms: 2.1.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  decimal.js-light@2.5.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deep-equal@2.2.3:
 | 
					  deep-equal@2.2.3:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      array-buffer-byte-length: 1.0.1
 | 
					      array-buffer-byte-length: 1.0.1
 | 
				
			||||||
@@ -3633,6 +3838,11 @@ snapshots:
 | 
				
			|||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      esutils: 2.0.3
 | 
					      esutils: 2.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dom-helpers@5.2.1:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/runtime': 7.25.6
 | 
				
			||||||
 | 
					      csstype: 3.1.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  drizzle-kit@0.24.2:
 | 
					  drizzle-kit@0.24.2:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      '@drizzle-team/brocli': 0.10.1
 | 
					      '@drizzle-team/brocli': 0.10.1
 | 
				
			||||||
@@ -4037,8 +4247,12 @@ snapshots:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  esutils@2.0.3: {}
 | 
					  esutils@2.0.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  eventemitter3@4.0.7: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fast-deep-equal@3.1.3: {}
 | 
					  fast-deep-equal@3.1.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fast-equals@5.0.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fast-glob@3.3.2:
 | 
					  fast-glob@3.3.2:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      '@nodelib/fs.stat': 2.0.5
 | 
					      '@nodelib/fs.stat': 2.0.5
 | 
				
			||||||
@@ -4227,6 +4441,8 @@ snapshots:
 | 
				
			|||||||
      hasown: 2.0.2
 | 
					      hasown: 2.0.2
 | 
				
			||||||
      side-channel: 1.0.6
 | 
					      side-channel: 1.0.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  internmap@2.0.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  invariant@2.2.4:
 | 
					  invariant@2.2.4:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      loose-envify: 1.4.0
 | 
					      loose-envify: 1.4.0
 | 
				
			||||||
@@ -4414,6 +4630,8 @@ snapshots:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  lodash.merge@4.6.2: {}
 | 
					  lodash.merge@4.6.2: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lodash@4.17.21: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loose-envify@1.4.0:
 | 
					  loose-envify@1.4.0:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      js-tokens: 4.0.0
 | 
					      js-tokens: 4.0.0
 | 
				
			||||||
@@ -4657,6 +4875,10 @@ snapshots:
 | 
				
			|||||||
      react: 18.3.1
 | 
					      react: 18.3.1
 | 
				
			||||||
      scheduler: 0.23.2
 | 
					      scheduler: 0.23.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-icons@5.3.0(react@18.3.1):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      react: 18.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react-is@16.13.1: {}
 | 
					  react-is@16.13.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react-remove-scroll-bar@2.3.6(@types/react@18.3.5)(react@18.3.1):
 | 
					  react-remove-scroll-bar@2.3.6(@types/react@18.3.5)(react@18.3.1):
 | 
				
			||||||
@@ -4678,6 +4900,14 @@ snapshots:
 | 
				
			|||||||
    optionalDependencies:
 | 
					    optionalDependencies:
 | 
				
			||||||
      '@types/react': 18.3.5
 | 
					      '@types/react': 18.3.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-smooth@4.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      fast-equals: 5.0.1
 | 
				
			||||||
 | 
					      prop-types: 15.8.1
 | 
				
			||||||
 | 
					      react: 18.3.1
 | 
				
			||||||
 | 
					      react-dom: 18.3.1(react@18.3.1)
 | 
				
			||||||
 | 
					      react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react-style-singleton@2.2.1(@types/react@18.3.5)(react@18.3.1):
 | 
					  react-style-singleton@2.2.1(@types/react@18.3.5)(react@18.3.1):
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      get-nonce: 1.0.1
 | 
					      get-nonce: 1.0.1
 | 
				
			||||||
@@ -4687,6 +4917,15 @@ snapshots:
 | 
				
			|||||||
    optionalDependencies:
 | 
					    optionalDependencies:
 | 
				
			||||||
      '@types/react': 18.3.5
 | 
					      '@types/react': 18.3.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@babel/runtime': 7.25.6
 | 
				
			||||||
 | 
					      dom-helpers: 5.2.1
 | 
				
			||||||
 | 
					      loose-envify: 1.4.0
 | 
				
			||||||
 | 
					      prop-types: 15.8.1
 | 
				
			||||||
 | 
					      react: 18.3.1
 | 
				
			||||||
 | 
					      react-dom: 18.3.1(react@18.3.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  react@18.3.1:
 | 
					  react@18.3.1:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      loose-envify: 1.4.0
 | 
					      loose-envify: 1.4.0
 | 
				
			||||||
@@ -4699,6 +4938,23 @@ snapshots:
 | 
				
			|||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      picomatch: 2.3.1
 | 
					      picomatch: 2.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recharts-scale@0.4.5:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      decimal.js-light: 2.5.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recharts@2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      clsx: 2.1.1
 | 
				
			||||||
 | 
					      eventemitter3: 4.0.7
 | 
				
			||||||
 | 
					      lodash: 4.17.21
 | 
				
			||||||
 | 
					      react: 18.3.1
 | 
				
			||||||
 | 
					      react-dom: 18.3.1(react@18.3.1)
 | 
				
			||||||
 | 
					      react-is: 16.13.1
 | 
				
			||||||
 | 
					      react-smooth: 4.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
 | 
				
			||||||
 | 
					      recharts-scale: 0.4.5
 | 
				
			||||||
 | 
					      tiny-invariant: 1.3.3
 | 
				
			||||||
 | 
					      victory-vendor: 36.9.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reflect.getprototypeof@1.0.6:
 | 
					  reflect.getprototypeof@1.0.6:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      call-bind: 1.0.7
 | 
					      call-bind: 1.0.7
 | 
				
			||||||
@@ -4709,6 +4965,8 @@ snapshots:
 | 
				
			|||||||
      globalthis: 1.0.4
 | 
					      globalthis: 1.0.4
 | 
				
			||||||
      which-builtin-type: 1.1.4
 | 
					      which-builtin-type: 1.1.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  regenerator-runtime@0.14.1: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  regexp.prototype.flags@1.5.2:
 | 
					  regexp.prototype.flags@1.5.2:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      call-bind: 1.0.7
 | 
					      call-bind: 1.0.7
 | 
				
			||||||
@@ -4945,6 +5203,8 @@ snapshots:
 | 
				
			|||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      any-promise: 1.3.0
 | 
					      any-promise: 1.3.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tiny-invariant@1.3.3: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  to-regex-range@5.0.1:
 | 
					  to-regex-range@5.0.1:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      is-number: 7.0.0
 | 
					      is-number: 7.0.0
 | 
				
			||||||
@@ -5034,6 +5294,23 @@ snapshots:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  util-deprecate@1.0.2: {}
 | 
					  util-deprecate@1.0.2: {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  victory-vendor@36.9.2:
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@types/d3-array': 3.2.1
 | 
				
			||||||
 | 
					      '@types/d3-ease': 3.0.2
 | 
				
			||||||
 | 
					      '@types/d3-interpolate': 3.0.4
 | 
				
			||||||
 | 
					      '@types/d3-scale': 4.0.8
 | 
				
			||||||
 | 
					      '@types/d3-shape': 3.1.6
 | 
				
			||||||
 | 
					      '@types/d3-time': 3.0.3
 | 
				
			||||||
 | 
					      '@types/d3-timer': 3.0.2
 | 
				
			||||||
 | 
					      d3-array: 3.2.4
 | 
				
			||||||
 | 
					      d3-ease: 3.0.1
 | 
				
			||||||
 | 
					      d3-interpolate: 3.0.1
 | 
				
			||||||
 | 
					      d3-scale: 4.0.2
 | 
				
			||||||
 | 
					      d3-shape: 3.2.0
 | 
				
			||||||
 | 
					      d3-time: 3.1.0
 | 
				
			||||||
 | 
					      d3-timer: 3.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  which-boxed-primitive@1.0.2:
 | 
					  which-boxed-primitive@1.0.2:
 | 
				
			||||||
    dependencies:
 | 
					    dependencies:
 | 
				
			||||||
      is-bigint: 1.0.4
 | 
					      is-bigint: 1.0.4
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 15 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 8.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/gib_pfp.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/gib_pfp.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 760 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/videos/techtrackeriosdemo.mp4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/videos/techtrackeriosdemo.mp4
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								public/videos/techtrackerwebdemo.mp4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/videos/techtrackerwebdemo.mp4
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -5,9 +5,9 @@ import { type Metadata } from "next";
 | 
				
			|||||||
import { ThemeProvider } from "~/components/theme/themeprovider"
 | 
					import { ThemeProvider } from "~/components/theme/themeprovider"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const metadata: Metadata = {
 | 
					export const metadata: Metadata = {
 | 
				
			||||||
  title: "Create T3 App",
 | 
					  title: "Gabriel's Portfolio",
 | 
				
			||||||
  description: "Generated by create-t3-app",
 | 
					  description: "A website to showcase my work & projects",
 | 
				
			||||||
  icons: [{ rel: "icon", url: "/favicon.ico" }],
 | 
					  icons: [{ rel: "icon", url: "/favicon.png" }],
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function RootLayout({
 | 
					export default function RootLayout({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,24 @@
 | 
				
			|||||||
import Link from "next/link";
 | 
					import { ThemeToggle } from "~/components/theme/themetoggle";
 | 
				
			||||||
import { ModeToggle } from "~/components/theme/themetoggle";
 | 
					import { PFPName } from "~/components/general/pfpname";
 | 
				
			||||||
 | 
					import AboutMe from "~/components/general/aboutme";
 | 
				
			||||||
 | 
					import TechChart from "~/components/general/techchart";
 | 
				
			||||||
 | 
					import TechTracker from "~/components/projects/techtracker";
 | 
				
			||||||
 | 
					//import Image from "next/image";
 | 
				
			||||||
 | 
					//import Link from "next/link";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function HomePage() {
 | 
					export default function HomePage() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <main className="min-h-screen">
 | 
					    <main className="min-h-screen">
 | 
				
			||||||
      <div className="flex flex-row items-end justify-end">
 | 
					      <div className="flex flex-row items-end justify-end">
 | 
				
			||||||
        <div className="mr-8 mt-6">
 | 
					        <div className="mr-8 mt-6">
 | 
				
			||||||
          <ModeToggle />
 | 
					          <ThemeToggle />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					      <PFPName />
 | 
				
			||||||
 | 
					      <AboutMe />
 | 
				
			||||||
 | 
					      <TechChart />
 | 
				
			||||||
 | 
					      <h1 className="text-3xl font-semibold text-center my-8">Projects</h1>
 | 
				
			||||||
 | 
					      <TechTracker />
 | 
				
			||||||
    </main>
 | 
					    </main>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/components/general/aboutme.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/components/general/aboutme.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					const AboutMe = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section className="my-6 flex flex-col items-center justify-center">
 | 
				
			||||||
 | 
					      <h2 className="text-3xl font-semibold mb-4">About Me</h2>
 | 
				
			||||||
 | 
					      <p className="w-5/6 md:w-1/2 lg:w-1/3 mx-auto leading-relaxed indent-5">
 | 
				
			||||||
 | 
					        I am a recent USM graduate with a Bachelor's degree in Computer Science.
 | 
				
			||||||
 | 
					        Despite my short time in Software Engineering, I have an extensive portfolio
 | 
				
			||||||
 | 
					        of Web Applications & broad range of knowledge & experience in many different
 | 
				
			||||||
 | 
					        stacks & technologies. You can also be sure that any project I create will be
 | 
				
			||||||
 | 
					        completely self-hosted on my Fedora Server!
 | 
				
			||||||
 | 
					      </p>
 | 
				
			||||||
 | 
					      <p className="w-5/6 md:w-1/2 lg:w-1/3 mx-auto leading-relaxed indent-5 mt-1">
 | 
				
			||||||
 | 
					        I am a big fan of TypeScript and I have been
 | 
				
			||||||
 | 
					        exclusively using it in my web projects for the past year with frameworks such as 
 | 
				
			||||||
 | 
					        Next.js & React Native. I also have experience building applications & backends
 | 
				
			||||||
 | 
					        using the technologies listed below!
 | 
				
			||||||
 | 
					      </p>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default AboutMe;
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/components/general/pfpname.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/components/general/pfpname.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					import Image from "next/image";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function PFPName() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="flex flex-row items-center justify-center">
 | 
				
			||||||
 | 
					      <Image src={"/gib_pfp.jpg"} alt={"Gabriel's Profile Picture"}
 | 
				
			||||||
 | 
					        width={80} height={80} className="rounded-full my-2"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <div className="mx-4 text-center my-auto">
 | 
				
			||||||
 | 
					        <h1 className="text-4xl font-bold">Gabriel Brown</h1>
 | 
				
			||||||
 | 
					        <h2 className="text-2xl font-semibold">Full Stack Developer</h2>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								src/components/general/techchart.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/components/general/techchart.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					"use client"
 | 
				
			||||||
 | 
					import { Bar, BarChart, XAxis, YAxis } from "recharts"
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Card,
 | 
				
			||||||
 | 
					  CardContent,
 | 
				
			||||||
 | 
					  CardHeader,
 | 
				
			||||||
 | 
					} from "~/components/ui/card"
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  type ChartConfig,
 | 
				
			||||||
 | 
					  ChartContainer,
 | 
				
			||||||
 | 
					  ChartTooltip,
 | 
				
			||||||
 | 
					  ChartTooltipContent,
 | 
				
			||||||
 | 
					} from "~/components/ui/chart"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const chartData = [
 | 
				
			||||||
 | 
					  { technology: "Linux", proficiency: 95 },
 | 
				
			||||||
 | 
					  { technology: "Docker", proficiency: 90 },
 | 
				
			||||||
 | 
					  { technology: "TypeScript", proficiency: 85 },
 | 
				
			||||||
 | 
					  { technology: "Next.js", proficiency: 80 },
 | 
				
			||||||
 | 
					  { technology: "React", proficiency: 80 },
 | 
				
			||||||
 | 
					  { technology: "React Native", proficiency: 75 },
 | 
				
			||||||
 | 
					  { technology: "Java", proficiency: 75 },
 | 
				
			||||||
 | 
					  { technology: "PHP", proficiency: 70 },
 | 
				
			||||||
 | 
					  { technology: "Python", proficiency: 70 },
 | 
				
			||||||
 | 
					  { technology: "Swift", proficiency: 60 },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const chartConfig = {
 | 
				
			||||||
 | 
					  proficiency: {
 | 
				
			||||||
 | 
					    label: "Proficiency",
 | 
				
			||||||
 | 
					    color: "hsl(var(--chart-1))",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					} satisfies ChartConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Component() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Card className="max-w-xl mx-auto">
 | 
				
			||||||
 | 
					      <CardHeader/>
 | 
				
			||||||
 | 
					      <CardContent>
 | 
				
			||||||
 | 
					        <ChartContainer config={chartConfig}>
 | 
				
			||||||
 | 
					          <BarChart
 | 
				
			||||||
 | 
					            accessibilityLayer
 | 
				
			||||||
 | 
					            data={chartData}
 | 
				
			||||||
 | 
					            layout="vertical"
 | 
				
			||||||
 | 
					            margin={{
 | 
				
			||||||
 | 
					              left: 60,
 | 
				
			||||||
 | 
					              right: 60,
 | 
				
			||||||
 | 
					              top: 0,
 | 
				
			||||||
 | 
					              bottom: 0,
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <XAxis
 | 
				
			||||||
 | 
					              type="number"
 | 
				
			||||||
 | 
					              dataKey="proficiency"
 | 
				
			||||||
 | 
					              domain={[0, 100]}
 | 
				
			||||||
 | 
					              tickCount={0}
 | 
				
			||||||
 | 
					              axisLine={false}
 | 
				
			||||||
 | 
					              tickLine={false}
 | 
				
			||||||
 | 
					              fontSize={12}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <YAxis
 | 
				
			||||||
 | 
					              dataKey="technology"
 | 
				
			||||||
 | 
					              type="category"
 | 
				
			||||||
 | 
					              tickLine={false}
 | 
				
			||||||
 | 
					              axisLine={false}
 | 
				
			||||||
 | 
					              width={90}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <ChartTooltip
 | 
				
			||||||
 | 
					              cursor={false}
 | 
				
			||||||
 | 
					              content={<ChartTooltipContent />}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <Bar 
 | 
				
			||||||
 | 
					              dataKey="proficiency" 
 | 
				
			||||||
 | 
					              fill="var(--color-proficiency)" 
 | 
				
			||||||
 | 
					              radius={[0, 4, 4, 0]}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </BarChart>
 | 
				
			||||||
 | 
					        </ChartContainer>
 | 
				
			||||||
 | 
					      </CardContent>
 | 
				
			||||||
 | 
					    </Card>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										73
									
								
								src/components/projects/techtracker.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/components/projects/techtracker.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Accordion,
 | 
				
			||||||
 | 
					  AccordionContent,
 | 
				
			||||||
 | 
					  AccordionItem,
 | 
				
			||||||
 | 
					  AccordionTrigger,
 | 
				
			||||||
 | 
					} from "~/components/ui/accordion"
 | 
				
			||||||
 | 
					import Link from "next/link";
 | 
				
			||||||
 | 
					import { FaGithub } from "react-icons/fa";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function TechTracker() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <section className="my-6 flex flex-col items-center justify-center m-auto">
 | 
				
			||||||
 | 
					      <Accordion type="single" collapsible className="w-1/3">
 | 
				
			||||||
 | 
					        <AccordionItem value="item-1">
 | 
				
			||||||
 | 
					          <AccordionTrigger>
 | 
				
			||||||
 | 
					            <h1 className="text-2xl font-semibold text-center mx-auto">Tech Tracker</h1>
 | 
				
			||||||
 | 
					          </AccordionTrigger>
 | 
				
			||||||
 | 
					          <AccordionContent>
 | 
				
			||||||
 | 
					            <div className="flex flex-col">
 | 
				
			||||||
 | 
					              <div className="flex flex-row my-4 mx-auto">
 | 
				
			||||||
 | 
					                <Link href="https://techtracker.gbrown.org">
 | 
				
			||||||
 | 
					                  <h2 className="text-lg font-semibold text-center">
 | 
				
			||||||
 | 
					                    Tech Tracker Web Application
 | 
				
			||||||
 | 
					                  </h2>
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					                <Link href="https://git.gbrown.org/gib/Tech_Tracker_Web">
 | 
				
			||||||
 | 
					                  < FaGithub className="my-auto ml-2" size={22} />
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p className="indent-4">
 | 
				
			||||||
 | 
					                A Next.js Web Application that allows City of Gulfport IT Employees to
 | 
				
			||||||
 | 
					                update their status throughout the day using the T3 Stack which includes
 | 
				
			||||||
 | 
					                TypeScript, TailwindCSS, Auth.js, PostgreSQL, Drizzle, & Shadcnui.
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					              <video
 | 
				
			||||||
 | 
					                src="/videos/techtrackerwebdemo.mp4"
 | 
				
			||||||
 | 
					                autoPlay
 | 
				
			||||||
 | 
					                loop
 | 
				
			||||||
 | 
					                muted
 | 
				
			||||||
 | 
					                playsInline
 | 
				
			||||||
 | 
					                className="max-w-full h-auto rounded-lg shadow-lg my-4"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div className="flex flex-col">
 | 
				
			||||||
 | 
					              <div className="flex flex-row my-4 mx-auto">
 | 
				
			||||||
 | 
					                <h2 className="text-lg font-semibold text-center">
 | 
				
			||||||
 | 
					                  Tech Tracker Native iOS Application
 | 
				
			||||||
 | 
					                </h2>
 | 
				
			||||||
 | 
					                <Link href="https://git.gbrown.org/gib/Tech_Tracker_iOS">
 | 
				
			||||||
 | 
					                  < FaGithub className="my-auto ml-2" size={22} />
 | 
				
			||||||
 | 
					                </Link>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p className="indent-4">
 | 
				
			||||||
 | 
					                A Native iOS Application written in Swift & Distributed to City of 
 | 
				
			||||||
 | 
					                Gulfport IT Employees using TestFlight. This application uses APIs
 | 
				
			||||||
 | 
					                provided by the Next.js Tech Tracker Web Application.
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					              <video
 | 
				
			||||||
 | 
					                src="/videos/techtrackeriosdemo.mp4"
 | 
				
			||||||
 | 
					                autoPlay
 | 
				
			||||||
 | 
					                loop
 | 
				
			||||||
 | 
					                muted
 | 
				
			||||||
 | 
					                playsInline
 | 
				
			||||||
 | 
					                className="rounded-lg shadow-lg my-4 mx-auto w-[200px]"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </AccordionContent>
 | 
				
			||||||
 | 
					        </AccordionItem>
 | 
				
			||||||
 | 
					      </Accordion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -1,40 +1,20 @@
 | 
				
			|||||||
"use client"
 | 
					"use client"
 | 
				
			||||||
 | 
					 | 
				
			||||||
import * as React from "react"
 | 
					import * as React from "react"
 | 
				
			||||||
import { Moon, Sun } from "lucide-react"
 | 
					import { Moon, Sun } from "lucide-react"
 | 
				
			||||||
import { useTheme } from "next-themes"
 | 
					import { useTheme } from "next-themes"
 | 
				
			||||||
 | 
					 | 
				
			||||||
import { Button } from "~/components/ui/button"
 | 
					import { Button } from "~/components/ui/button"
 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  DropdownMenu,
 | 
					 | 
				
			||||||
  DropdownMenuContent,
 | 
					 | 
				
			||||||
  DropdownMenuItem,
 | 
					 | 
				
			||||||
  DropdownMenuTrigger,
 | 
					 | 
				
			||||||
} from "~/components/ui/dropdown-menu"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function ModeToggle() {
 | 
					 | 
				
			||||||
  const { setTheme } = useTheme()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ThemeToggle() {
 | 
				
			||||||
 | 
					  const { setTheme, resolvedTheme } = useTheme()
 | 
				
			||||||
 | 
					  const toggleTheme = () => {
 | 
				
			||||||
 | 
					    if (resolvedTheme === "dark") setTheme("light")
 | 
				
			||||||
 | 
					    else setTheme("dark")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <DropdownMenu>
 | 
					    <Button variant="outline" size="icon" onClick={() => toggleTheme()}>
 | 
				
			||||||
      <DropdownMenuTrigger asChild>
 | 
					      <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
 | 
				
			||||||
        <Button variant="outline" size="icon">
 | 
					      <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
 | 
				
			||||||
          <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
 | 
					      <span className="sr-only">Toggle theme</span>
 | 
				
			||||||
          <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
 | 
					    </Button>
 | 
				
			||||||
          <span className="sr-only">Toggle theme</span>
 | 
					 | 
				
			||||||
        </Button>
 | 
					 | 
				
			||||||
      </DropdownMenuTrigger>
 | 
					 | 
				
			||||||
      <DropdownMenuContent align="end">
 | 
					 | 
				
			||||||
        <DropdownMenuItem onClick={() => setTheme("light")}>
 | 
					 | 
				
			||||||
          Light
 | 
					 | 
				
			||||||
        </DropdownMenuItem>
 | 
					 | 
				
			||||||
        <DropdownMenuItem onClick={() => setTheme("dark")}>
 | 
					 | 
				
			||||||
          Dark
 | 
					 | 
				
			||||||
        </DropdownMenuItem>
 | 
					 | 
				
			||||||
        <DropdownMenuItem onClick={() => setTheme("system")}>
 | 
					 | 
				
			||||||
          System
 | 
					 | 
				
			||||||
        </DropdownMenuItem>
 | 
					 | 
				
			||||||
      </DropdownMenuContent>
 | 
					 | 
				
			||||||
    </DropdownMenu>
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										76
									
								
								src/components/ui/card.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/components/ui/card.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					import * as React from "react"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { cn } from "~/lib/utils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Card = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLDivElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <div
 | 
				
			||||||
 | 
					    ref={ref}
 | 
				
			||||||
 | 
					    className={cn(
 | 
				
			||||||
 | 
					      "rounded-xl border bg-card text-card-foreground shadow",
 | 
				
			||||||
 | 
					      className
 | 
				
			||||||
 | 
					    )}
 | 
				
			||||||
 | 
					    {...props}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					Card.displayName = "Card"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CardHeader = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLDivElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <div
 | 
				
			||||||
 | 
					    ref={ref}
 | 
				
			||||||
 | 
					    className={cn("flex flex-col space-y-1.5 p-6", className)}
 | 
				
			||||||
 | 
					    {...props}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					CardHeader.displayName = "CardHeader"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CardTitle = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLParagraphElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLHeadingElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <h3
 | 
				
			||||||
 | 
					    ref={ref}
 | 
				
			||||||
 | 
					    className={cn("font-semibold leading-none tracking-tight", className)}
 | 
				
			||||||
 | 
					    {...props}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					CardTitle.displayName = "CardTitle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CardDescription = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLParagraphElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLParagraphElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <p
 | 
				
			||||||
 | 
					    ref={ref}
 | 
				
			||||||
 | 
					    className={cn("text-sm text-muted-foreground", className)}
 | 
				
			||||||
 | 
					    {...props}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					CardDescription.displayName = "CardDescription"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CardContent = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLDivElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					CardContent.displayName = "CardContent"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CardFooter = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.HTMLAttributes<HTMLDivElement>
 | 
				
			||||||
 | 
					>(({ className, ...props }, ref) => (
 | 
				
			||||||
 | 
					  <div
 | 
				
			||||||
 | 
					    ref={ref}
 | 
				
			||||||
 | 
					    className={cn("flex items-center p-6 pt-0", className)}
 | 
				
			||||||
 | 
					    {...props}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					CardFooter.displayName = "CardFooter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
 | 
				
			||||||
							
								
								
									
										370
									
								
								src/components/ui/chart.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								src/components/ui/chart.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,370 @@
 | 
				
			|||||||
 | 
					"use client"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as React from "react"
 | 
				
			||||||
 | 
					import * as RechartsPrimitive from "recharts"
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  NameType,
 | 
				
			||||||
 | 
					  Payload,
 | 
				
			||||||
 | 
					  ValueType,
 | 
				
			||||||
 | 
					} from "recharts/types/component/DefaultTooltipContent"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { cn } from "~/lib/utils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Format: { THEME_NAME: CSS_SELECTOR }
 | 
				
			||||||
 | 
					const THEMES = { light: "", dark: ".dark" } as const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ChartConfig = {
 | 
				
			||||||
 | 
					  [k in string]: {
 | 
				
			||||||
 | 
					    label?: React.ReactNode
 | 
				
			||||||
 | 
					    icon?: React.ComponentType
 | 
				
			||||||
 | 
					  } & (
 | 
				
			||||||
 | 
					    | { color?: string; theme?: never }
 | 
				
			||||||
 | 
					    | { color?: never; theme: Record<keyof typeof THEMES, string> }
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ChartContextProps = {
 | 
				
			||||||
 | 
					  config: ChartConfig
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartContext = React.createContext<ChartContextProps | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useChart() {
 | 
				
			||||||
 | 
					  const context = React.useContext(ChartContext)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!context) {
 | 
				
			||||||
 | 
					    throw new Error("useChart must be used within a <ChartContainer />")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return context
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartContainer = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.ComponentProps<"div"> & {
 | 
				
			||||||
 | 
					    config: ChartConfig
 | 
				
			||||||
 | 
					    children: React.ComponentProps<
 | 
				
			||||||
 | 
					      typeof RechartsPrimitive.ResponsiveContainer
 | 
				
			||||||
 | 
					    >["children"]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					>(({ id, className, children, config, ...props }, ref) => {
 | 
				
			||||||
 | 
					  const uniqueId = React.useId()
 | 
				
			||||||
 | 
					  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ChartContext.Provider value={{ config }}>
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        data-chart={chartId}
 | 
				
			||||||
 | 
					        ref={ref}
 | 
				
			||||||
 | 
					        className={cn(
 | 
				
			||||||
 | 
					          "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
 | 
				
			||||||
 | 
					          className
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        {...props}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <ChartStyle id={chartId} config={config} />
 | 
				
			||||||
 | 
					        <RechartsPrimitive.ResponsiveContainer>
 | 
				
			||||||
 | 
					          {children}
 | 
				
			||||||
 | 
					        </RechartsPrimitive.ResponsiveContainer>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </ChartContext.Provider>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					ChartContainer.displayName = "Chart"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
 | 
				
			||||||
 | 
					  const colorConfig = Object.entries(config).filter(
 | 
				
			||||||
 | 
					    ([_, config]) => config.theme || config.color
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!colorConfig.length) {
 | 
				
			||||||
 | 
					    return null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <style
 | 
				
			||||||
 | 
					      dangerouslySetInnerHTML={{
 | 
				
			||||||
 | 
					        __html: Object.entries(THEMES)
 | 
				
			||||||
 | 
					          .map(
 | 
				
			||||||
 | 
					            ([theme, prefix]) => `
 | 
				
			||||||
 | 
					${prefix} [data-chart=${id}] {
 | 
				
			||||||
 | 
					${colorConfig
 | 
				
			||||||
 | 
					  .map(([key, itemConfig]) => {
 | 
				
			||||||
 | 
					    const color =
 | 
				
			||||||
 | 
					      itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
 | 
				
			||||||
 | 
					      itemConfig.color
 | 
				
			||||||
 | 
					    return color ? `  --color-${key}: ${color};` : null
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  .join("\n")}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					          .join("\n"),
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartTooltip = RechartsPrimitive.Tooltip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartTooltipContent = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
 | 
				
			||||||
 | 
					    React.ComponentProps<"div"> & {
 | 
				
			||||||
 | 
					      hideLabel?: boolean
 | 
				
			||||||
 | 
					      hideIndicator?: boolean
 | 
				
			||||||
 | 
					      indicator?: "line" | "dot" | "dashed"
 | 
				
			||||||
 | 
					      nameKey?: string
 | 
				
			||||||
 | 
					      labelKey?: string
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					>(
 | 
				
			||||||
 | 
					  (
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      active,
 | 
				
			||||||
 | 
					      payload,
 | 
				
			||||||
 | 
					      className,
 | 
				
			||||||
 | 
					      indicator = "dot",
 | 
				
			||||||
 | 
					      hideLabel = false,
 | 
				
			||||||
 | 
					      hideIndicator = false,
 | 
				
			||||||
 | 
					      label,
 | 
				
			||||||
 | 
					      labelFormatter,
 | 
				
			||||||
 | 
					      labelClassName,
 | 
				
			||||||
 | 
					      formatter,
 | 
				
			||||||
 | 
					      color,
 | 
				
			||||||
 | 
					      nameKey,
 | 
				
			||||||
 | 
					      labelKey,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    ref
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    const { config } = useChart()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const tooltipLabel = React.useMemo(() => {
 | 
				
			||||||
 | 
					      if (hideLabel || !payload?.length) {
 | 
				
			||||||
 | 
					        return null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const [item] = payload
 | 
				
			||||||
 | 
					      const key = `${labelKey || item.dataKey || item.name || "value"}`
 | 
				
			||||||
 | 
					      const itemConfig = getPayloadConfigFromPayload(config, item, key)
 | 
				
			||||||
 | 
					      const value =
 | 
				
			||||||
 | 
					        !labelKey && typeof label === "string"
 | 
				
			||||||
 | 
					          ? config[label as keyof typeof config]?.label || label
 | 
				
			||||||
 | 
					          : itemConfig?.label
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (labelFormatter) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					          <div className={cn("font-medium", labelClassName)}>
 | 
				
			||||||
 | 
					            {labelFormatter(value, payload)}
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!value) {
 | 
				
			||||||
 | 
					        return null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return <div className={cn("font-medium", labelClassName)}>{value}</div>
 | 
				
			||||||
 | 
					    }, [
 | 
				
			||||||
 | 
					      label,
 | 
				
			||||||
 | 
					      labelFormatter,
 | 
				
			||||||
 | 
					      payload,
 | 
				
			||||||
 | 
					      hideLabel,
 | 
				
			||||||
 | 
					      labelClassName,
 | 
				
			||||||
 | 
					      config,
 | 
				
			||||||
 | 
					      labelKey,
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!active || !payload?.length) {
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const nestLabel = payload.length === 1 && indicator !== "dot"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        ref={ref}
 | 
				
			||||||
 | 
					        className={cn(
 | 
				
			||||||
 | 
					          "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
 | 
				
			||||||
 | 
					          className
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {!nestLabel ? tooltipLabel : null}
 | 
				
			||||||
 | 
					        <div className="grid gap-1.5">
 | 
				
			||||||
 | 
					          {payload.map((item, index) => {
 | 
				
			||||||
 | 
					            const key = `${nameKey || item.name || item.dataKey || "value"}`
 | 
				
			||||||
 | 
					            const itemConfig = getPayloadConfigFromPayload(config, item, key)
 | 
				
			||||||
 | 
					            const indicatorColor = color || item.payload.fill || item.color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					              <div
 | 
				
			||||||
 | 
					                key={item.dataKey}
 | 
				
			||||||
 | 
					                className={cn(
 | 
				
			||||||
 | 
					                  "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
 | 
				
			||||||
 | 
					                  indicator === "dot" && "items-center"
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                {formatter && item?.value !== undefined && item.name ? (
 | 
				
			||||||
 | 
					                  formatter(item.value, item.name, item, index, item.payload)
 | 
				
			||||||
 | 
					                ) : (
 | 
				
			||||||
 | 
					                  <>
 | 
				
			||||||
 | 
					                    {itemConfig?.icon ? (
 | 
				
			||||||
 | 
					                      <itemConfig.icon />
 | 
				
			||||||
 | 
					                    ) : (
 | 
				
			||||||
 | 
					                      !hideIndicator && (
 | 
				
			||||||
 | 
					                        <div
 | 
				
			||||||
 | 
					                          className={cn(
 | 
				
			||||||
 | 
					                            "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                              "h-2.5 w-2.5": indicator === "dot",
 | 
				
			||||||
 | 
					                              "w-1": indicator === "line",
 | 
				
			||||||
 | 
					                              "w-0 border-[1.5px] border-dashed bg-transparent":
 | 
				
			||||||
 | 
					                                indicator === "dashed",
 | 
				
			||||||
 | 
					                              "my-0.5": nestLabel && indicator === "dashed",
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          style={
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                              "--color-bg": indicatorColor,
 | 
				
			||||||
 | 
					                              "--color-border": indicatorColor,
 | 
				
			||||||
 | 
					                            } as React.CSSProperties
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                      )
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                    <div
 | 
				
			||||||
 | 
					                      className={cn(
 | 
				
			||||||
 | 
					                        "flex flex-1 justify-between leading-none",
 | 
				
			||||||
 | 
					                        nestLabel ? "items-end" : "items-center"
 | 
				
			||||||
 | 
					                      )}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <div className="grid gap-1.5">
 | 
				
			||||||
 | 
					                        {nestLabel ? tooltipLabel : null}
 | 
				
			||||||
 | 
					                        <span className="text-muted-foreground">
 | 
				
			||||||
 | 
					                          {itemConfig?.label || item.name}
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                      {item.value && (
 | 
				
			||||||
 | 
					                        <span className="font-mono font-medium tabular-nums text-foreground">
 | 
				
			||||||
 | 
					                          {item.value.toLocaleString()}
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                      )}
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </>
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					ChartTooltipContent.displayName = "ChartTooltip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartLegend = RechartsPrimitive.Legend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChartLegendContent = React.forwardRef<
 | 
				
			||||||
 | 
					  HTMLDivElement,
 | 
				
			||||||
 | 
					  React.ComponentProps<"div"> &
 | 
				
			||||||
 | 
					    Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
 | 
				
			||||||
 | 
					      hideIcon?: boolean
 | 
				
			||||||
 | 
					      nameKey?: string
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					>(
 | 
				
			||||||
 | 
					  (
 | 
				
			||||||
 | 
					    { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
 | 
				
			||||||
 | 
					    ref
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
 | 
					    const { config } = useChart()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!payload?.length) {
 | 
				
			||||||
 | 
					      return null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        ref={ref}
 | 
				
			||||||
 | 
					        className={cn(
 | 
				
			||||||
 | 
					          "flex items-center justify-center gap-4",
 | 
				
			||||||
 | 
					          verticalAlign === "top" ? "pb-3" : "pt-3",
 | 
				
			||||||
 | 
					          className
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {payload.map((item) => {
 | 
				
			||||||
 | 
					          const key = `${nameKey || item.dataKey || "value"}`
 | 
				
			||||||
 | 
					          const itemConfig = getPayloadConfigFromPayload(config, item, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          return (
 | 
				
			||||||
 | 
					            <div
 | 
				
			||||||
 | 
					              key={item.value}
 | 
				
			||||||
 | 
					              className={cn(
 | 
				
			||||||
 | 
					                "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {itemConfig?.icon && !hideIcon ? (
 | 
				
			||||||
 | 
					                <itemConfig.icon />
 | 
				
			||||||
 | 
					              ) : (
 | 
				
			||||||
 | 
					                <div
 | 
				
			||||||
 | 
					                  className="h-2 w-2 shrink-0 rounded-[2px]"
 | 
				
			||||||
 | 
					                  style={{
 | 
				
			||||||
 | 
					                    backgroundColor: item.color,
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					              {itemConfig?.label}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					ChartLegendContent.displayName = "ChartLegend"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Helper to extract item config from a payload.
 | 
				
			||||||
 | 
					function getPayloadConfigFromPayload(
 | 
				
			||||||
 | 
					  config: ChartConfig,
 | 
				
			||||||
 | 
					  payload: unknown,
 | 
				
			||||||
 | 
					  key: string
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  if (typeof payload !== "object" || payload === null) {
 | 
				
			||||||
 | 
					    return undefined
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const payloadPayload =
 | 
				
			||||||
 | 
					    "payload" in payload &&
 | 
				
			||||||
 | 
					    typeof payload.payload === "object" &&
 | 
				
			||||||
 | 
					    payload.payload !== null
 | 
				
			||||||
 | 
					      ? payload.payload
 | 
				
			||||||
 | 
					      : undefined
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let configLabelKey: string = key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (
 | 
				
			||||||
 | 
					    key in payload &&
 | 
				
			||||||
 | 
					    typeof payload[key as keyof typeof payload] === "string"
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    configLabelKey = payload[key as keyof typeof payload] as string
 | 
				
			||||||
 | 
					  } else if (
 | 
				
			||||||
 | 
					    payloadPayload &&
 | 
				
			||||||
 | 
					    key in payloadPayload &&
 | 
				
			||||||
 | 
					    typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    configLabelKey = payloadPayload[
 | 
				
			||||||
 | 
					      key as keyof typeof payloadPayload
 | 
				
			||||||
 | 
					    ] as string
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return configLabelKey in config
 | 
				
			||||||
 | 
					    ? config[configLabelKey]
 | 
				
			||||||
 | 
					    : config[key as keyof typeof config]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export {
 | 
				
			||||||
 | 
					  ChartContainer,
 | 
				
			||||||
 | 
					  ChartTooltip,
 | 
				
			||||||
 | 
					  ChartTooltipContent,
 | 
				
			||||||
 | 
					  ChartLegend,
 | 
				
			||||||
 | 
					  ChartLegendContent,
 | 
				
			||||||
 | 
					  ChartStyle,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user