diff --git a/app/layout.tsx b/app/layout.tsx index 1cc366b..f469a84 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import { TooltipProvider } from "@/components/ui/tooltip"; +import { Toaster } from "@/components/ui/toaster"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -29,7 +30,8 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} antialiased overflow-x-hidden`} > - {children} +
{children}
+
diff --git a/app/page.tsx b/app/page.tsx index 42fa022..0561d29 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,10 +1,13 @@ "use client"; -import { FriendsHomeSect } from "@/components/FriendsOnlineSection"; -import { GameCard } from "@/components/gameCard"; -import { HomeLoggedInHeader } from "@/components/loggedInHeader"; -import { QuickTopUI, QuickTopUILogoPart } from "@/components/QuickTopUI"; -import { VerifiedIcon } from "@/components/RobloxIcons"; +import { + BestFriendsHomeSect, + FriendsHomeSect +} from "@/components/roblox/FriendsOnline"; +import { GameCard } from "@/components/roblox/GameCard"; +import { HomeLoggedInHeader } from "@/components/site/HomeUserHeader"; +import { OutfitSelector } from "@/components/site/OutfitQuickChooser"; +import { QuickTopUI, QuickTopUILogoPart } from "@/components/site/QuickTopUI"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Card, CardContent } from "@/components/ui/card"; import { @@ -13,6 +16,7 @@ import { } from "@/lib/omniRecommendation"; import { loadThumbnails } from "@/lib/thumbnailLoader"; import { AlertTriangleIcon } from "lucide-react"; +import Image from "next/image"; import { useEffect, useState } from "react"; export default function Home() { @@ -36,58 +40,67 @@ export default function Home() { }, []); return ( -
- - - - -
- - - Warning - - This is work in progess, you can follow the development - process on GitHub. - - -
-
- {!rec ? ( - - -
-
- {"Loading..."} + <> + +
+ + + +
+ + +
+ + + Warning + + This is work in progess, you can follow the + development process on GitHub. + + +
+
+ {!rec ? ( + + +
+
+ {"Loading..."} +
-
- - - ) : ( - rec.sorts - .filter((a) => SORTS_ALLOWED_IDS.includes(a.topicId)) - .map((sort, idx) => ( -
-

{sort.topic}

-
- {(sort.recommendationList || []).map( - (recommendation, idxb) => { - const game = - rec.contentMetadata.Game[ - recommendation.contentId.toString() - ]; - return ( - - ); - } - )} + + + ) : ( + rec.sorts + .filter((a) => + SORTS_ALLOWED_IDS.includes(a.topicId) + ) + .map((sort, idx) => ( +
+

+ {sort.topic} +

+
+ {(sort.recommendationList || []).map( + (recommendation, idxb) => { + const game = + rec.contentMetadata.Game[ + recommendation.contentId.toString() + ]; + return ( + + ); + } + )} +
-
- )) - )} + )) + )} +
-
+ ); } diff --git a/bun.lock b/bun.lock index 5a8e2b4..8b898b2 100644 --- a/bun.lock +++ b/bun.lock @@ -43,6 +43,7 @@ "lucide-react": "^0.525.0", "next": "15.1.6", "next-themes": "^0.4.6", + "noblox.js": "^6.2.0", "react": "^19.0.0", "react-day-picker": "^9.8.0", "react-dom": "^19.0.0", @@ -134,6 +135,8 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@microsoft/signalr": ["@microsoft/signalr@8.0.7", "", { "dependencies": { "abort-controller": "^3.0.0", "eventsource": "^2.0.2", "fetch-cookie": "^2.0.3", "node-fetch": "^2.6.7", "ws": "^7.4.5" } }, "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw=="], + "@next/env": ["@next/env@15.1.6", "", {}, "sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w=="], "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw=="], @@ -302,6 +305,10 @@ "@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], "ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], @@ -314,10 +321,26 @@ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], + + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "aws-sign2": ["aws-sign2@0.7.0", "", {}, "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="], + + "aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="], + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + "bluebird": ["bluebird@2.11.0", "", {}, "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -328,6 +351,14 @@ "caniuse-lite": ["caniuse-lite@1.0.30001727", "", {}, "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q=="], + "caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="], + + "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], + + "cheerio": ["cheerio@1.1.2", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg=="], + + "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], @@ -346,10 +377,18 @@ "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], @@ -376,12 +415,16 @@ "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + "dashdash": ["dashdash@1.14.1", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g=="], + "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], "date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="], "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], @@ -392,8 +435,18 @@ "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="], + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "ecc-jsbn": ["ecc-jsbn@0.1.2", "", { "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw=="], + "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], @@ -402,30 +455,66 @@ "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], + + "entities": ["entities@5.0.0", "", {}, "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + "eventsource": ["eventsource@2.0.2", "", {}, "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "extsprintf": ["extsprintf@1.3.0", "", {}, "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-equals": ["fast-equals@5.2.2", "", {}, "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw=="], "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + "fetch-cookie": ["fetch-cookie@2.2.0", "", { "dependencies": { "set-cookie-parser": "^2.4.8", "tough-cookie": "^4.0.0" } }, "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ=="], + + "figlet": ["figlet@1.8.2", "", { "bin": { "figlet": "bin/index.js" } }, "sha512-iPCpE9B/rOcjewIzDnagP9F2eySzGeHReX8WlrZQJkqFBk2wvq8gY0c6U6Hd2y9HnX1LQcYSeP7aEHoPt6sVKQ=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "forever-agent": ["forever-agent@0.6.1", "", {}, "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="], + + "form-data": ["form-data@2.3.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "getpass": ["getpass@0.1.7", "", { "dependencies": { "assert-plus": "^1.0.0" } }, "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng=="], + "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + "har-schema": ["har-schema@2.0.0", "", {}, "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="], + + "har-validator": ["har-validator@5.1.5", "", { "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "htmlparser2": ["htmlparser2@10.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.1", "entities": "^6.0.0" } }, "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g=="], + + "http-signature": ["http-signature@1.2.0", "", { "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], @@ -444,14 +533,28 @@ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isstream": ["isstream@0.1.2", "", {}, "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="], + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "jsbn": ["jsbn@0.1.1", "", {}, "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="], + + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "jsprim": ["jsprim@1.4.2", "", { "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.4.0", "verror": "1.10.0" } }, "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw=="], + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], @@ -468,6 +571,10 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], @@ -480,20 +587,36 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + "noblox.js": ["noblox.js@6.2.0", "", { "dependencies": { "@microsoft/signalr": "^8.0.7", "chalk": "^5.3.0", "cheerio": "^1.0.0-rc.10", "entities": "^5.0.0", "figlet": "^1.7.0", "postman-request": "^2.88.1-postman.34" } }, "sha512-LJZctENpuS3/iNQI/c1kPvmPdRhfZbiQLvMM0mXXwnApEO/6NXGlvYiBpMknBtHeDbTbrTaWa0BD6SeMn/z7Xw=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "oauth-sign": ["oauth-sign@0.9.0", "", {}, "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + + "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "performance-now": ["performance-now@2.1.0", "", {}, "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -516,8 +639,20 @@ "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + "postman-request": ["postman-request@2.88.1-postman.8-beta.1", "", { "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", "postman-url-encoder": "1.0.1", "qs": "~6.5.2", "safe-buffer": "^5.1.2", "stream-length": "^1.0.2", "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" } }, "sha512-deC5UZlM1VimFhQdPN1NcbQMvLEtpUCTHZHMXWNv6vyNW7H98O3MJGTlk2xTlzB9BOpU2MCCgXNOPeNP2SU6iA=="], + + "postman-url-encoder": ["postman-url-encoder@1.0.1", "", {}, "sha512-ned2lpcMpEG+n3ce2LEoGqUJeZsKNRYkViqKfJXe7rUQhLxjrrcp/lQ8TLycvX74lQZm52gkNVVgczmcJBOJ8w=="], + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + "psl": ["psl@1.15.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.5.3", "", {}, "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="], + + "querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], @@ -550,16 +685,24 @@ "recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="], + "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], + "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -574,6 +717,10 @@ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "sshpk": ["sshpk@1.18.0", "", { "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, "bin": { "sshpk-conv": "bin/sshpk-conv", "sshpk-sign": "bin/sshpk-sign", "sshpk-verify": "bin/sshpk-verify" } }, "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ=="], + + "stream-length": ["stream-length@1.0.2", "", { "dependencies": { "bluebird": "^2.6.2" } }, "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg=="], + "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="], "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -604,14 +751,30 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "tough-cookie": ["tough-cookie@2.5.0", "", { "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" } }, "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + + "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="], + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + "undici": ["undici@7.12.0", "", {}, "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], @@ -620,26 +783,48 @@ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "uuid": ["uuid@3.4.0", "", { "bin": { "uuid": "./bin/uuid" } }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="], + "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], + "verror": ["verror@1.10.0", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw=="], + "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "yaml": ["yaml@2.8.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ=="], "zod": ["zod@4.0.5", "", {}, "sha512-/5UuuRPStvHXu7RS+gmvRf4NXrNxpSllGwDnCBcJZtQsKrviYXm54yDGV2KYNLT5kq0lHGcl7lqWJLgSaG+tgA=="], "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "fetch-cookie/tough-cookie": ["tough-cookie@4.1.4", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag=="], + + "htmlparser2/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], diff --git a/components/FriendsOnlineSection.tsx b/components/FriendsOnlineSection.tsx deleted file mode 100644 index 957fe59..0000000 --- a/components/FriendsOnlineSection.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount"; -import { useFriendsHome } from "@/hooks/roblox/useFriendsHome"; -import LazyLoadedImage from "./lazyLoadedImage"; -import React from "react"; -import { VerifiedIcon } from "./RobloxIcons"; -import { useFriendsPresence } from "@/hooks/roblox/usePresence"; -import { StupidHoverThing } from "./MiscStuff"; - -export function FriendsHomeSect( - props: React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLDivElement - > -) { - const friends = useFriendsHome(); - const acct = useCurrentAccount(); - const presence = useFriendsPresence( - (!!friends ? friends : []).map((f) => f.id) - ); - - if (!friends) { - return <>; - } - - return ( -
- {/* */} -

Friends

-
-
-
- {friends.map((a) => { - const userStatus = presence.find( - (b) => b.userId === a.id - ); - const userPresence = userStatus?.userPresenceType || 0; - const borderColor = - userPresence === 1 - ? "border-blue bg-blue/50" - : userPresence === 2 - ? "border-green bg-green/50" - : userPresence === 3 - ? "border-yellow bg-yellow/50" - : userPresence === 0 - ? "border-surface2 bg-surface2/50" - : "border-red bg-red/50"; - const textColor = - userPresence === 1 - ? "text-blue" - : userPresence === 2 - ? "text-green" - : userPresence === 3 - ? "text-yellow" - : userPresence === 0 - ? "text-surface2" - : "text-red"; - const fillColor = - userPresence === 1 - ? "fill-blue" - : userPresence === 2 - ? "fill-green" - : userPresence === 3 - ? "fill-yellow" - : userPresence === 0 - ? "fill-surface2" - : "fill-red"; - - return ( -
- - - -

{a.displayName || a.name}

- {!a.hasVerifiedBadge ? ( - - ) : null} -
- } - > - - {a.displayName || a.name} - - - {!a.hasVerifiedBadge ? ( - - ) : null} - -
- ); - })} -
-
-
-
- ); -} diff --git a/components/MiscStuff.tsx b/components/MiscStuff.tsx deleted file mode 100644 index 232b370..0000000 --- a/components/MiscStuff.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { VerifiedIcon } from "./RobloxIcons"; -import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; - -export function StupidHoverThing({ children, text }: React.PropsWithChildren & { text: string | React.ReactNode }) { - return ( - - - {children} - - -

{text}

-
-
- ) -} diff --git a/components/QuickTopUI.tsx b/components/QuickTopUI.tsx deleted file mode 100644 index 101543a..0000000 --- a/components/QuickTopUI.tsx +++ /dev/null @@ -1,28 +0,0 @@ -"use client"; - -import { useRobuxBalance } from "@/hooks/roblox/useRobuxBalance"; -import { RobuxIcon } from "./RobloxIcons"; -import React from "react"; - -export const QuickTopUI = React.memo(function () { - const robux = useRobuxBalance(); - return ( -
-
-
- -

{robux || "???"}

-
-
-
- ); -}); - -export const QuickTopUILogoPart = React.memo(function () { - return ( -
- -

{"ocbwoy3-chan-blox"}

-
- ); -}); diff --git a/components/roblox/FriendCarousel.tsx b/components/roblox/FriendCarousel.tsx new file mode 100644 index 0000000..7ece789 --- /dev/null +++ b/components/roblox/FriendCarousel.tsx @@ -0,0 +1,198 @@ +import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount"; +import { useFriendsHome } from "@/hooks/roblox/useFriends"; +import { useFriendsPresence } from "@/hooks/roblox/usePresence"; +import React, { useEffect, useState } from "react"; +import LazyLoadedImage from "../util/LazyLoadedImage"; +import { StupidHoverThing } from "../util/MiscStuff"; +import { VerifiedIcon } from "./RobloxIcons"; + +export function FriendCarousel({ + friends: friendsUnsorted, + title, + dontSortByActivity, + ...props +}: React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLDivElement +> & { + title: string; + dontSortByActivity?: boolean; + friends: + | { + hasVerifiedBadge: boolean; + id: number; + name: string; + displayName: string; + }[] + | null + | false; +}) { + const acct = useCurrentAccount(); + const presence = useFriendsPresence( + (!!friendsUnsorted ? friendsUnsorted : []).map((f) => f.id) + ); + + const [friendsLabel, setFriendsLabel] = useState(""); + + const [friends, setFriends] = useState< + { + hasVerifiedBadge: boolean; + id: number; + name: string; + displayName: string; + }[] + >([]); + + useEffect(() => { + let numStudio = 0; + let numGame = 0; + let numOnline = 0; + for (const friend of friendsUnsorted || []) { + const st = presence.find((c) => c.userId === friend.id); + switch (st?.userPresenceType || 0) { + case 1: + numOnline += 1; + break; + case 2: + numGame += 1; + break; + case 3: + numStudio += 1; + break; + } + } + setFriendsLabel( + [ + `${friends.length}`, + numGame === 0 ? null : `${numGame} in-game`, + numStudio === 0 ? null : `${numStudio} studio` + ] + .filter((a) => !!a) + .join(" | ") + ); + + if (!friendsUnsorted) { + setFriends([]); + return; + } + setFriends( + friendsUnsorted.sort((a, b) => { + if (!!dontSortByActivity) return -10; + const userStatusA = presence.find((c) => c.userId === a.id); + const userStatusB = presence.find((c) => c.userId === b.id); + + return ( + (userStatusB?.userPresenceType || 0) - + (userStatusA?.userPresenceType || 0) + ); + }) + ); + }, [friendsUnsorted, presence, dontSortByActivity]); + + if (!friends || friends.length === 0) { + return <>; + } + + return ( +
+ {/* */} +

+ {title}{" "} + {friendsLabel} +

+
+
+ {/*
*/} + {friends.map((a) => { + const userStatus = presence.find( + (b) => b.userId === a.id + ); + const userPresence = userStatus?.userPresenceType || 0; + const borderColor = + userPresence === 1 + ? "border-blue/25 bg-blue/25" + : userPresence === 2 + ? "border-green/25 bg-green/25" + : userPresence === 3 + ? "border-yellow/25 bg-yellow/25" + : userPresence === 0 + ? "border-surface2/25 bg-surface2/25" + : "border-red/25 bg-red/25"; + const textColor = + userPresence === 1 + ? "text-blue" + : userPresence === 2 + ? "text-green" + : userPresence === 3 + ? "text-yellow" + : userPresence === 0 + ? "text-surface2" + : "text-red"; + const fillColor = + userPresence === 1 + ? "fill-blue" + : userPresence === 2 + ? "fill-green" + : userPresence === 3 + ? "fill-yellow" + : userPresence === 0 + ? "fill-surface2" + : "fill-red"; + + return ( + + +

{a.displayName || a.name}

+ {!a.hasVerifiedBadge ? ( + + ) : null} + { userPresence >= 2 ?

{userStatus?.lastLocation}

: <>} +
+
+ } + > +
+ + + + {a.displayName || a.name} + + {!a.hasVerifiedBadge ? ( + + ) : null} + +
+ + ); + })} + {/*
*/} +
+
+
+ ); +} diff --git a/components/roblox/FriendsOnline.tsx b/components/roblox/FriendsOnline.tsx new file mode 100644 index 0000000..165bd64 --- /dev/null +++ b/components/roblox/FriendsOnline.tsx @@ -0,0 +1,26 @@ +import { useFriendsHome } from "@/hooks/roblox/useFriends"; +import React from "react"; +import { FriendCarousel } from "./FriendCarousel"; +import { useBestFriends } from "@/hooks/roblox/useBestFriends"; + +export function FriendsHomeSect( + props: React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLDivElement + > +) { + const friends = useFriendsHome(); + + return ; +} + +export function BestFriendsHomeSect( + props: React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLDivElement + > +) { + const friends = useBestFriends(); + + return ; +} diff --git a/components/gameCard.tsx b/components/roblox/GameCard.tsx similarity index 96% rename from components/gameCard.tsx rename to components/roblox/GameCard.tsx index 20cdd23..444aa63 100644 --- a/components/gameCard.tsx +++ b/components/roblox/GameCard.tsx @@ -1,13 +1,13 @@ "use client"; import { ContentMetadata } from "@/lib/omniRecommendation"; -import LazyLoadedImage from "./lazyLoadedImage"; +import LazyLoadedImage from "../util/LazyLoadedImage"; import { ContextMenu, ContextMenuContent, ContextMenuSeparator, ContextMenuTrigger -} from "./ui/context-menu"; +} from "../ui/context-menu"; import { ContextMenuItem } from "@radix-ui/react-context-menu"; import React from "react"; diff --git a/components/RobloxIcons.tsx b/components/roblox/RobloxIcons.tsx similarity index 100% rename from components/RobloxIcons.tsx rename to components/roblox/RobloxIcons.tsx diff --git a/components/RobloxTooltipStuff.tsx b/components/roblox/RobloxTooltips.tsx similarity index 95% rename from components/RobloxTooltipStuff.tsx rename to components/roblox/RobloxTooltips.tsx index 63aef37..dbbab40 100644 --- a/components/RobloxTooltipStuff.tsx +++ b/components/roblox/RobloxTooltips.tsx @@ -2,9 +2,8 @@ import { PremiumIconSmall, VerifiedIcon } from "./RobloxIcons"; import { Tooltip, TooltipContent, - TooltipProvider, TooltipTrigger -} from "./ui/tooltip"; +} from "../ui/tooltip"; export function RobloxPremiumSmall(props: React.SVGProps) { return ( diff --git a/components/loggedInHeader.tsx b/components/site/HomeUserHeader.tsx similarity index 55% rename from components/loggedInHeader.tsx rename to components/site/HomeUserHeader.tsx index feac433..e5b2d3b 100644 --- a/components/loggedInHeader.tsx +++ b/components/site/HomeUserHeader.tsx @@ -1,21 +1,26 @@ "use client"; import React, { useEffect } from "react"; -import LazyLoadedImage from "./lazyLoadedImage"; -import { Alert, AlertDescription, AlertTitle } from "./ui/alert"; +import LazyLoadedImage from "../util/LazyLoadedImage"; +import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; import { OctagonXIcon } from "lucide-react"; -import { RobloxPremiumSmall, RobloxVerifiedSmall } from "./RobloxTooltipStuff"; +import { + RobloxPremiumSmall, + RobloxVerifiedSmall +} from "@/components/roblox/RobloxTooltips"; import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount"; -import { Skeleton } from "./ui/skeleton"; +import { Skeleton } from "../ui/skeleton"; import { useFriendsPresence } from "@/hooks/roblox/usePresence"; +import { useAccountSettings } from "@/hooks/roblox/useAccountSettings"; export function HomeLoggedInHeader() { const profile = useCurrentAccount(); + const accountSettings = useAccountSettings(); if (profile === false) { return (
- + Failed to fetch account info @@ -29,24 +34,26 @@ export function HomeLoggedInHeader() { const presence = useFriendsPresence(profile ? [profile.id] : []); - const userActivity = presence.find((b) => b.userId === profile?.id) + const userActivity = presence.find((b) => b.userId === profile?.id); const userPresence = userActivity?.userPresenceType; const borderColor = userPresence === 1 - ? "border-blue bg-blue/50" + ? "border-blue/25 bg-blue/25" : userPresence === 2 - ? "border-green bg-green/50" + ? "border-green/25 bg-green/25" : userPresence === 3 - ? "border-yellow bg-yellow/50" + ? "border-yellow/25 bg-yellow/25" : userPresence === 0 - ? "border-surface2 bg-surface2/50" - : "border-red bg-red/50"; + ? "border-surface2/25 bg-surface2/25" + : "border-red/25 bg-red/25"; + + const isLoaded = !!profile && !!accountSettings; return ( <> {/* */} -
- {!profile ? ( +
+ {!isLoaded ? ( ) : ( - {profile ? ( - <>Hello, {profile.displayName} + {isLoaded ? ( + <> + {!!accountSettings && + accountSettings.IsPremium === true + ? `Howdy, ${profile.displayName}` + : `${profile.displayName}`} + ) : ( <> )} - {/* TODO: Fetch the User's Roblox Premium subscription state */} - - + {!!accountSettings && + accountSettings.IsPremium === true ? ( + + ) : ( + <> + )} + {isLoaded ? ( + + ) : ( + <> + )} - {profile ? ( + {isLoaded ? ( <> @{profile.name} - {(!!userActivity && userPresence === 2) ? <> - {userActivity.lastLocation} : <> } + {!!userActivity && userPresence === 2 ? ( + <> - {userActivity.lastLocation} + ) : ( + <> + )} ) : ( diff --git a/components/site/OutfitQuickChooser.tsx b/components/site/OutfitQuickChooser.tsx new file mode 100644 index 0000000..c688d19 --- /dev/null +++ b/components/site/OutfitQuickChooser.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { useAvatarOutfits } from "@/hooks/roblox/useAvatarOutfits"; +import { Button } from "@/components/ui/button"; +import { cn, proxyFetch } from "@/lib/utils"; +import LazyLoadedImage from "../util/LazyLoadedImage"; +import { StupidHoverThing } from "../util/MiscStuff"; +import { loadThumbnails } from "@/lib/thumbnailLoader"; +import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount"; + +type OutfitSelectorProps = { + setVisible: (visible: boolean) => void; + updateOutfit: (outfit: { id: number }, acc: {id: number}) => Promise; +}; + +export function OutfitSelector({ setVisible, updateOutfit }: OutfitSelectorProps) { + const outfits = useAvatarOutfits(); + const acc = useCurrentAccount(); + + if (!outfits || !acc) return null; + + return ( +
+ + ))} +
+
+ ); +} diff --git a/components/site/QuickTopUI.tsx b/components/site/QuickTopUI.tsx new file mode 100644 index 0000000..856bf33 --- /dev/null +++ b/components/site/QuickTopUI.tsx @@ -0,0 +1,99 @@ +"use client"; + +import { useRobuxBalance } from "@/hooks/roblox/useRobuxBalance"; +import { RobuxIcon } from "../roblox/RobloxIcons"; +import React, { useState } from "react"; +import { Separator } from "../ui/separator"; +import { Bell, SettingsIcon, ShirtIcon } from "lucide-react"; +import { StupidHoverThing } from "../util/MiscStuff"; +import { toast } from "sonner"; +import { OutfitSelector } from "./OutfitQuickChooser"; +import { proxyFetch } from "@/lib/utils"; +import { loadThumbnails } from "@/lib/thumbnailLoader"; + +/** +requires csrf token cuz u cant use noblox.js on the web + +either go to https://roblox.com/my/avataar or the app to change ur fit +*/ +async function updateOutfit(outfit: { id: number }, acc: {id: number}) { + try { + const J = (await ( + await proxyFetch( + `https://avatar.roblox.com/v3/outfits/${outfit.id}/details` + ) + ).json()) as { + id: number; + name: string; + assets: any[]; + }; + await proxyFetch( + `https://avatar.roblox.com/v1/avatar/set-wearing-assets`, + { + method: "POST", + body: JSON.stringify({ + assetIds: J.assets.map(a=>a.id).filter(a=>!!a) + }) + } + ); + loadThumbnails([ + { + type: "AvatarHeadShot", + targetId: acc.id, + format: "webp", + size: "720x720" + } + ]).catch((a) => {}); + } catch {} +} + + + +export const QuickTopUI = React.memo(function () { + const robux = useRobuxBalance(); + const [isOutfitSelectorVisible, setIsOutfitSelectorVisible] = + useState(false); + return ( + <> + {/* {isOutfitSelectorVisible ? ( + + ) : ( + <> + )} */} +
+ {/* + + */} + + +
+ + {robux ? ( +

{robux || "???"}

+ ) : ( + <> + )} +
+
+
+ + ); +}); + +export const QuickTopUILogoPart = React.memo(function () { + return ( +
+ +

{"not roblox lol"}

+
+ ); +}); diff --git a/components/lazyLoadedImage.tsx b/components/util/LazyLoadedImage.tsx similarity index 93% rename from components/lazyLoadedImage.tsx rename to components/util/LazyLoadedImage.tsx index 5f930eb..90a7416 100644 --- a/components/lazyLoadedImage.tsx +++ b/components/util/LazyLoadedImage.tsx @@ -1,6 +1,6 @@ import React from "react"; import { useThumbnailURL } from "@/hooks/use-lazy-load"; -import { Skeleton } from "./ui/skeleton"; +import { Skeleton } from "../ui/skeleton"; import Image from "next/image"; interface LazyLoadedImageProps { diff --git a/components/util/MiscStuff.tsx b/components/util/MiscStuff.tsx new file mode 100644 index 0000000..8d727bb --- /dev/null +++ b/components/util/MiscStuff.tsx @@ -0,0 +1,16 @@ +import { TooltipProps } from "@radix-ui/react-tooltip"; +import { VerifiedIcon } from "../roblox/RobloxIcons"; +import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; + +export function StupidHoverThing({ children, text, ...props }: React.PropsWithChildren & TooltipProps & { text: string | React.ReactNode }) { + return ( + + + {children} + + + {text} + + + ) +} diff --git a/hooks/roblox/useAccountSettings.ts b/hooks/roblox/useAccountSettings.ts new file mode 100644 index 0000000..1e1217e --- /dev/null +++ b/hooks/roblox/useAccountSettings.ts @@ -0,0 +1,67 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useCurrentAccount } from "./useCurrentAccount"; +import { proxyFetch } from "@/lib/utils"; + +type AccountSettings = { + ChangeUsernameEnabled: boolean + + /* determines if the account owner is a roblox admin */ + IsAdmin: boolean, + + PreviousUserNames: string, + + /* censored out email */ + UserEmail: string, + + UserAbove13: boolean, + + /* does the user have roblox premium */ + IsPremium: boolean, + + /* ingame chat */ + IsGameChatSettingEnabled: boolean +} + +export function useAccountSettings() { + const acct = useCurrentAccount(); + const [accountSettings, setAccountSettings] = useState(null); + + useEffect(() => { + if (!acct) return; + + let cancelled = false; + + const fetchSetttings = async () => { + if (!acct || cancelled) return; + try { + const res = await proxyFetch( + `https://www.roblox.com/my/settings/json` + ); + const data = await res.json(); + if (!cancelled) setAccountSettings(data); + } catch { + if (!cancelled) setAccountSettings(false); + } + }; + + fetchSetttings(); + + const handleTransaction = () => { + fetchSetttings(); + }; + + window.addEventListener("settingTransactionCompletedEvent", handleTransaction); + + return () => { + cancelled = true; + window.removeEventListener( + "settingTransactionCompletedEvent", + handleTransaction + ); + }; + }, [acct]); + + return accountSettings; +} diff --git a/hooks/roblox/useAvatarOutfits.ts b/hooks/roblox/useAvatarOutfits.ts new file mode 100644 index 0000000..e7a82e1 --- /dev/null +++ b/hooks/roblox/useAvatarOutfits.ts @@ -0,0 +1,63 @@ +// https://avatar.roblox.com/v2/avatar/users/1083030325/outfits?isEditable=true&itemsPerPage=50&outfitType=Avatar + +"use client"; + +import { useEffect, useState } from "react"; +import { useCurrentAccount } from "./useCurrentAccount"; +import { proxyFetch } from "@/lib/utils"; +import { loadThumbnails } from "@/lib/thumbnailLoader"; + +type Outfit = { + name: string, + id: number +} + +export function useAvatarOutfits() { + const acct = useCurrentAccount(); + const [outfits, setOutfits] = useState(null); + + useEffect(() => { + if (!acct) return; + + let cancelled = false; + + const fetchSetttings = async () => { + if (!acct || cancelled) return; + try { + const res = await proxyFetch( + `https://avatar.roblox.com/v2/avatar/users/${acct.id}/outfits?page=1&itemsPerPage=25&isEditable=true` + ); + const data = await res.json() as {data: Outfit[]}; + if (!cancelled) { + setOutfits(data.data); + loadThumbnails(data.data.map(a=>({ + type: "Outfit", + targetId: a.id, + format: "webp", + size: "420x420" + }))).catch(a=>{}) + } + } catch { + if (!cancelled) setOutfits(false); + } + }; + + fetchSetttings(); + + const handleTransaction = () => { + fetchSetttings(); + }; + + window.addEventListener("avatarTransactionCompletedEvent", handleTransaction); + + return () => { + cancelled = true; + window.removeEventListener( + "avatarTransactionCompletedEvent", + handleTransaction + ); + }; + }, [acct]); + + return outfits; +} diff --git a/hooks/roblox/useBestFriends.ts b/hooks/roblox/useBestFriends.ts new file mode 100644 index 0000000..9b6feeb --- /dev/null +++ b/hooks/roblox/useBestFriends.ts @@ -0,0 +1,89 @@ +"use client"; + +// https://friends.roblox.com/v1/users/1083030325/friends/find?userSort=1 + +import { useEffect, useState } from "react"; +import { useCurrentAccount } from "./useCurrentAccount"; +import { proxyFetch } from "@/lib/utils"; +import { loadThumbnails } from "@/lib/thumbnailLoader"; + +let isFetching = false; +let cachedData: any = null; + +export function useBestFriends() { + const acct = useCurrentAccount(); + const [friends, setFriends] = useState< + | { + hasVerifiedBadge: boolean; + id: number; + name: string; + displayName: string; + }[] + | null + | false + >(cachedData); + + useEffect(() => { + let cancelled = false; + if (!acct) return; + if (isFetching) { + const IN = setInterval(() => { + if (cachedData !== null) { + if (!cancelled) setFriends(cachedData); + clearInterval(IN); + } + }, 50); + return () => { + clearInterval(IN); + cancelled = true; + }; + } + isFetching = true; + (async () => { + const BestFriendIDs = JSON.parse(window.localStorage.getItem("BestFriendsStore") || "[]") as number[] + const friendsAPICall2 = await proxyFetch( + `https://users.roblox.com/v1/users`, + { + method: "POST", + body: JSON.stringify({ + userIds: BestFriendIDs, + excludeBannedUsers: false + }) + } + ); + const J2 = (await friendsAPICall2.json()) as { + data: { + hasVerifiedBadge: boolean; + id: number; + name: string; + displayName: string; + }[]; + }; + loadThumbnails( + J2.data.map((a) => ({ + type: "AvatarHeadShot", + size: "420x420", + targetId: a.id, + format: "webp" + })) + ).catch(() => {}); + const friendsList = BestFriendIDs.map((a) => { + const x = J2.data.find((b) => b.id === a); + return { + id: a, + hasVerifiedBadge: x?.hasVerifiedBadge || false, + name: x?.name || "?", + displayName: x?.displayName || "?" + }; + }); + if (!cancelled) setFriends(friendsList); + cachedData = friendsList; + isFetching = false; + })(); + return () => { + cancelled = true; + }; + }, [acct]); + + return friends; +} diff --git a/hooks/roblox/useFriendsHome.ts b/hooks/roblox/useFriends.ts similarity index 86% rename from hooks/roblox/useFriendsHome.ts rename to hooks/roblox/useFriends.ts index 61b652e..eda1fd5 100644 --- a/hooks/roblox/useFriendsHome.ts +++ b/hooks/roblox/useFriends.ts @@ -41,17 +41,19 @@ export function useFriendsHome() { isFetching = true; (async () => { const friendsAPICall = await proxyFetch( - `https://friends.roblox.com/v1/users/${acct.id}/friends/find?userSort=1` + `https://friends.roblox.com/v1/users/${acct.id}/friends` // /find?userSort=1 ); const J = (await friendsAPICall.json()) as { - PageItems: { id: number }[]; + data: { id: number }[]; + // PageItems: { id: number }[]; // /find }; const friendsAPICall2 = await proxyFetch( `https://users.roblox.com/v1/users`, { method: "POST", body: JSON.stringify({ - userIds: J.PageItems.map((a) => a.id), + userIds: J.data.map((a) => a.id), + // userIds: J.PageItems.map((a) => a.id), excludeBannedUsers: false }) } @@ -72,7 +74,7 @@ export function useFriendsHome() { format: "webp" })) ).catch(() => {}); - const friendsList = J.PageItems.map((a) => { + const friendsList = J.data.map((a) => { // J.PageItems /find const x = J2.data.find((b) => b.id === a.id); return { id: a.id, diff --git a/hooks/roblox/usePresence.ts b/hooks/roblox/usePresence.ts index f9d73bc..6c5fd09 100644 --- a/hooks/roblox/usePresence.ts +++ b/hooks/roblox/usePresence.ts @@ -57,7 +57,9 @@ async function fetchPresence(acctId: number) { ); if (!res.ok) { - throw new Error(`API request failed with status ${res.status}`); + console.log(`[usePresence] API Error ${res.status} ${res.statusText}`) + return + // throw new Error(`API request failed with status ${res.status}`); } const json = await res.json(); diff --git a/lib/thumbnailLoader.ts b/lib/thumbnailLoader.ts index 766d19c..eb4d36e 100644 --- a/lib/thumbnailLoader.ts +++ b/lib/thumbnailLoader.ts @@ -14,7 +14,7 @@ export type AssetThumbnail = { }; export type ThumbnailRequest = { - type: "GameThumbnail" | "AvatarHeadShot"; + type: "GameThumbnail" | "AvatarHeadShot" | "Outfit" | `${string}`; targetId: number; format: "webp"; size: string; diff --git a/package.json b/package.json index f347f7f..8e9ad63 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "lucide-react": "^0.525.0", "next": "15.1.6", "next-themes": "^0.4.6", + "noblox.js": "^6.2.0", "react": "^19.0.0", "react-day-picker": "^9.8.0", "react-dom": "^19.0.0", diff --git a/public/bg.png b/public/bg.png new file mode 100644 index 0000000..19a9234 Binary files /dev/null and b/public/bg.png differ