useBestFriends();
This commit is contained in:
@@ -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`}
|
||||
>
|
||||
<TooltipProvider>
|
||||
{children}
|
||||
<main>{children}</main>
|
||||
<Toaster />
|
||||
</TooltipProvider>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
123
app/page.tsx
123
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 (
|
||||
<div className="overflow-scroll no-scrollbar w-screen max-h-screen h-screen antialiased overflow-x-hidden">
|
||||
<QuickTopUI />
|
||||
<QuickTopUILogoPart />
|
||||
<HomeLoggedInHeader />
|
||||
<FriendsHomeSect className="pt-8" />
|
||||
<div className="justify-center w-screen px-8 pt-6">
|
||||
<Alert variant="default" className="space-x-2">
|
||||
<AlertTriangleIcon />
|
||||
<AlertTitle>Warning</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is work in progess, you can follow the development
|
||||
process on GitHub.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
<div className="p-4 space-y-8 no-scrollbar">
|
||||
{!rec ? (
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="h-[200px] flex items-center justify-center">
|
||||
<div className="animate-pulse text-muted-foreground">
|
||||
{"Loading..."}
|
||||
<>
|
||||
<Image src={window.localStorage.BgImageUrl || "/bg.png"} width={1920} height={1080} className="w-screen h-screen bg-blend-hard-light fixed top-0 left-0 blur-lg opacity-25" alt=""/>
|
||||
<div className="z-10 isolate overflow-scroll no-scrollbar w-screen max-h-screen h-screen antialiased overflow-x-hidden">
|
||||
<QuickTopUI />
|
||||
<QuickTopUILogoPart />
|
||||
<HomeLoggedInHeader />
|
||||
<div className="h-4" />
|
||||
<BestFriendsHomeSect className="pt-2" />
|
||||
<FriendsHomeSect className="pt-2" />
|
||||
<div className="justify-center w-screen px-8 pt-6">
|
||||
<Alert variant="default" className="bg-base/50 space-x-2">
|
||||
<AlertTriangleIcon />
|
||||
<AlertTitle>Warning</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is work in progess, you can follow the
|
||||
development process on GitHub.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
<div className="p-4 space-y-8 no-scrollbar">
|
||||
{!rec ? (
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="h-[200px] flex items-center justify-center">
|
||||
<div className="animate-pulse text-muted-foreground">
|
||||
{"Loading..."}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
rec.sorts
|
||||
.filter((a) => SORTS_ALLOWED_IDS.includes(a.topicId))
|
||||
.map((sort, idx) => (
|
||||
<div key={idx}>
|
||||
<h1 className="text-2xl pb-2">{sort.topic}</h1>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{(sort.recommendationList || []).map(
|
||||
(recommendation, idxb) => {
|
||||
const game =
|
||||
rec.contentMetadata.Game[
|
||||
recommendation.contentId.toString()
|
||||
];
|
||||
return (
|
||||
<GameCard
|
||||
key={idxb}
|
||||
game={game}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
rec.sorts
|
||||
.filter((a) =>
|
||||
SORTS_ALLOWED_IDS.includes(a.topicId)
|
||||
)
|
||||
.map((sort, idx) => (
|
||||
<div key={idx}>
|
||||
<h1 className="text-2xl pb-2">
|
||||
{sort.topic}
|
||||
</h1>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{(sort.recommendationList || []).map(
|
||||
(recommendation, idxb) => {
|
||||
const game =
|
||||
rec.contentMetadata.Game[
|
||||
recommendation.contentId.toString()
|
||||
];
|
||||
return (
|
||||
<GameCard
|
||||
key={idxb}
|
||||
game={game}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
185
bun.lock
185
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=="],
|
||||
|
||||
@@ -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>,
|
||||
HTMLDivElement
|
||||
>
|
||||
) {
|
||||
const friends = useFriendsHome();
|
||||
const acct = useCurrentAccount();
|
||||
const presence = useFriendsPresence(
|
||||
(!!friends ? friends : []).map((f) => f.id)
|
||||
);
|
||||
|
||||
if (!friends) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
{/* <button onClick={()=>console.log(acct,presence,friends)}>debug</button> */}
|
||||
<h1 className="text-2xl pb-2 pl-4">Friends</h1>
|
||||
<div className="bg-base p-4 rounded-xl flex flex-col gap-2 px-4 no-scrollbar">
|
||||
<div
|
||||
className="flex items-center gap-4 overflow-x-auto overflow-y-visible no-scrollbar pb-2 -mx-4 w-screen scrollbar-thin scrollbar-thumb-surface2 scrollbar-track-surface0"
|
||||
style={{
|
||||
scrollSnapType: "x mandatory",
|
||||
WebkitOverflowScrolling: "touch",
|
||||
scrollbarWidth: "none"
|
||||
}}
|
||||
>
|
||||
<div className="w-8" />
|
||||
{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 (
|
||||
<div
|
||||
key={a.id}
|
||||
className="flex flex-col min-w-[6.5rem]"
|
||||
>
|
||||
<LazyLoadedImage
|
||||
imgId={`AvatarHeadShot_${a.id}`}
|
||||
alt={a.name}
|
||||
className={`w-24 h-24 rounded-full border-2 ${borderColor} object-cover shadow-xl`}
|
||||
/>
|
||||
<span
|
||||
className={`text-xs ${textColor} mt-1 text-center flex items-center justify-center gap-1 max-w-[6.5rem] overflow-hidden line-clamp-2`}
|
||||
>
|
||||
<StupidHoverThing
|
||||
text={
|
||||
<span className="space-x-1 flex items-center">
|
||||
<p>{a.displayName || a.name}</p>
|
||||
{!a.hasVerifiedBadge ? (
|
||||
<VerifiedIcon
|
||||
useDefault
|
||||
className={`w-4 h-4 shrink-0`}
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span className="line-clamp-1 overflow-hidden text-ellipsis">
|
||||
{a.displayName || a.name}
|
||||
</span>
|
||||
</StupidHoverThing>
|
||||
{!a.hasVerifiedBadge ? (
|
||||
<VerifiedIcon
|
||||
className={`text-base ${fillColor} w-3 h-3 shrink-0`}
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="w-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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 (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
{children}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="bg-surface0 text-text m-2">
|
||||
<p className="text-sm flex items-center">{text}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
@@ -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 (
|
||||
<div className="z-50 absolute top-4 right-4 p-4 flex gap-4 items-center">
|
||||
<div className="rounded-full bg-crust/50 flex items-center p-2">
|
||||
<div className="px-2 font-sans text-blue text-xl flex items-center">
|
||||
<RobuxIcon className="w-6 h-6" />
|
||||
<p className="pl-1">{robux || "???"}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const QuickTopUILogoPart = React.memo(function () {
|
||||
return (
|
||||
<div className="z-50 relative top-4 left-4 p-4 flex gap-4 items-center text-blue">
|
||||
<img src="/icon-128.webp" className="-m-1 w-8 h-8" alt="" />
|
||||
<p className="mt-2">{"ocbwoy3-chan-blox"}</p>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
198
components/roblox/FriendCarousel.tsx
Normal file
198
components/roblox/FriendCarousel.tsx
Normal file
@@ -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>,
|
||||
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<string>("");
|
||||
|
||||
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 (
|
||||
<div {...props}>
|
||||
{/* <button onClick={()=>console.log(acct,presence,friends)}>debug</button> */}
|
||||
<h1 className="text-2xl pt-4 pl-4 -mb-4">
|
||||
{title}{" "}
|
||||
<span className="text-overlay1 text-sm pl-2">{friendsLabel}</span>
|
||||
</h1>
|
||||
<div className="rounded-xl flex flex-col gap-2 px-4 no-scrollbar">
|
||||
<div
|
||||
className="flex p-8 items-center gap-4 overflow-x-auto overflow-y-visible no-scrollbar pb-2 -mx-4 w-screen scrollbar-thin scrollbar-thumb-surface2 scrollbar-track-surface0"
|
||||
style={{
|
||||
scrollSnapType: "x mandatory",
|
||||
WebkitOverflowScrolling: "touch",
|
||||
scrollbarWidth: "none"
|
||||
}}
|
||||
>
|
||||
{/* <div className="w-8" /> */}
|
||||
{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 (
|
||||
<StupidHoverThing
|
||||
key={a.id}
|
||||
delayDuration={0}
|
||||
text={
|
||||
<div className="text-center items-center justify-center content-center">
|
||||
<span className="space-x-1 flex items-center">
|
||||
<p>{a.displayName || a.name}</p>
|
||||
{!a.hasVerifiedBadge ? (
|
||||
<VerifiedIcon
|
||||
useDefault
|
||||
className={`w-4 h-4 shrink-0`}
|
||||
/>
|
||||
) : null}
|
||||
{ userPresence >= 2 ? <p>{userStatus?.lastLocation}</p> : <></>}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
key={a.id}
|
||||
className="flex flex-col min-w-[6.5rem]"
|
||||
>
|
||||
<LazyLoadedImage
|
||||
imgId={`AvatarHeadShot_${a.id}`}
|
||||
alt={a.name}
|
||||
className={`w-24 h-24 rounded-full border-2 ${borderColor} object-cover shadow-xl`}
|
||||
/>
|
||||
<span
|
||||
className={`text-xs ${textColor} mt-1 text-center flex items-center justify-center gap-1 max-w-[6.5rem] overflow-hidden line-clamp-2`}
|
||||
>
|
||||
<span className="line-clamp-1 overflow-hidden text-ellipsis">
|
||||
{a.displayName || a.name}
|
||||
</span>
|
||||
{!a.hasVerifiedBadge ? (
|
||||
<VerifiedIcon
|
||||
className={`text-base ${fillColor} w-3 h-3 shrink-0`}
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
</StupidHoverThing>
|
||||
);
|
||||
})}
|
||||
{/* <div className="w-8" /> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
26
components/roblox/FriendsOnline.tsx
Normal file
26
components/roblox/FriendsOnline.tsx
Normal file
@@ -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>,
|
||||
HTMLDivElement
|
||||
>
|
||||
) {
|
||||
const friends = useFriendsHome();
|
||||
|
||||
return <FriendCarousel {...props} title="Friends" friends={friends} />;
|
||||
}
|
||||
|
||||
export function BestFriendsHomeSect(
|
||||
props: React.DetailedHTMLProps<
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
>
|
||||
) {
|
||||
const friends = useBestFriends();
|
||||
|
||||
return <FriendCarousel {...props} title="Best Friends" dontSortByActivity friends={friends} />;
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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<SVGSVGElement>) {
|
||||
return (
|
||||
@@ -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 (
|
||||
<div className="justify-center w-screen px-8 py-6">
|
||||
<Alert variant="destructive" className="space-x-2">
|
||||
<Alert variant="destructive" className="bg-base/50 space-x-2">
|
||||
<OctagonXIcon />
|
||||
<AlertTitle>Failed to fetch account info</AlertTitle>
|
||||
<AlertDescription>
|
||||
@@ -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 (
|
||||
<>
|
||||
{/* <button onClick={()=>console.log(userPresence)}>debug this</button> */}
|
||||
<div className="flex items-center gap-6 bg-base rounded-xl px-8 py-6 w-fit mt-8 ml-0">
|
||||
{!profile ? (
|
||||
<div className="flex items-center gap-6 rounded-xl px-8 py-6 w-fit mt-8 ml-0">
|
||||
{!isLoaded ? (
|
||||
<Skeleton className="w-28 h-28 rounded-full" />
|
||||
) : (
|
||||
<LazyLoadedImage
|
||||
@@ -57,22 +64,39 @@ export function HomeLoggedInHeader() {
|
||||
)}
|
||||
<div className="flex flex-col justify-center">
|
||||
<span className="text-3xl font-bold text-text flex items-center gap-2">
|
||||
{profile ? (
|
||||
<>Hello, {profile.displayName}</>
|
||||
{isLoaded ? (
|
||||
<>
|
||||
{!!accountSettings &&
|
||||
accountSettings.IsPremium === true
|
||||
? `Howdy, ${profile.displayName}`
|
||||
: `${profile.displayName}`}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Skeleton className="w-96 h-8 rounded-lg" />
|
||||
</>
|
||||
)}
|
||||
{/* TODO: Fetch the User's Roblox Premium subscription state */}
|
||||
<RobloxPremiumSmall className="w-6 h-6 fill-transparent" />
|
||||
<RobloxVerifiedSmall className="w-6 h-6 fill-blue text-base" />
|
||||
{!!accountSettings &&
|
||||
accountSettings.IsPremium === true ? (
|
||||
<RobloxPremiumSmall className="w-6 h-6 fill-transparent" />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{isLoaded ? (
|
||||
<RobloxVerifiedSmall className="w-6 h-6 fill-blue text-base" />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</span>
|
||||
<span className="text-base font-mono text-subtext0 mt-1">
|
||||
{profile ? (
|
||||
{isLoaded ? (
|
||||
<>
|
||||
@{profile.name}
|
||||
{(!!userActivity && userPresence === 2) ? <> - {userActivity.lastLocation}</> : <></> }
|
||||
{!!userActivity && userPresence === 2 ? (
|
||||
<> - {userActivity.lastLocation}</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Skeleton className="w-64 h-6 rounded-lg" />
|
||||
52
components/site/OutfitQuickChooser.tsx
Normal file
52
components/site/OutfitQuickChooser.tsx
Normal file
@@ -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<void>;
|
||||
};
|
||||
|
||||
export function OutfitSelector({ setVisible, updateOutfit }: OutfitSelectorProps) {
|
||||
const outfits = useAvatarOutfits();
|
||||
const acc = useCurrentAccount();
|
||||
|
||||
if (!outfits || !acc) return null;
|
||||
|
||||
return (
|
||||
<div className="z-30 isolate absolute inset-0 flex items-center justify-center bg-crust/50">
|
||||
<button
|
||||
className="z-10 absolute w-screen h-screen cursor-default"
|
||||
onClick={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
<div className="z-20 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4 p-8 bg-crust/90 rounded-xl">
|
||||
{(outfits || []).map((outfit: { id: number; name: string }) => (
|
||||
<button
|
||||
key={outfit.id}
|
||||
className="hover:bg-base/50 rounded-lg"
|
||||
onClick={async () => {
|
||||
updateOutfit(outfit,acc);
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<StupidHoverThing delayDuration={0} text={outfit.name}>
|
||||
<LazyLoadedImage
|
||||
imgId={`Outfit_${outfit.id}`}
|
||||
alt={outfit.name}
|
||||
className="w-32 h-32 rounded-md"
|
||||
/>
|
||||
</StupidHoverThing>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
99
components/site/QuickTopUI.tsx
Normal file
99
components/site/QuickTopUI.tsx
Normal file
@@ -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<boolean>(false);
|
||||
return (
|
||||
<>
|
||||
{/* {isOutfitSelectorVisible ? (
|
||||
<OutfitSelector setVisible={setIsOutfitSelectorVisible} updateOutfit={updateOutfit} />
|
||||
) : (
|
||||
<></>
|
||||
)} */}
|
||||
<div className="z-50 absolute top-4 right-4 p-4 flex gap-2 items-center text-blue/75">
|
||||
{/* <StupidHoverThing text="Change Outfit">
|
||||
<button
|
||||
className="rounded-full bg-crust/50 flex items-center p-2"
|
||||
onClick={() => {
|
||||
setIsOutfitSelectorVisible((a) => !a);
|
||||
}}
|
||||
>
|
||||
<ShirtIcon />
|
||||
</button>
|
||||
</StupidHoverThing> */}
|
||||
|
||||
<StupidHoverThing
|
||||
text={!robux ? "Loading..." : `You have ${robux} Robux`}
|
||||
>
|
||||
<div className="rounded-full bg-crust/50 flex items-center p-2">
|
||||
<RobuxIcon className="w-6 h-6" />
|
||||
{robux ? (
|
||||
<p className="pl-1">{robux || "???"}</p>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</StupidHoverThing>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const QuickTopUILogoPart = React.memo(function () {
|
||||
return (
|
||||
<div className="z-[15] relative top-4 left-4 p-4 flex gap-4 items-center text-blue">
|
||||
<img src="/icon-512.webp" className="-m-1 w-8 h-8" alt="" />
|
||||
<p className="mt-2">{"not roblox lol"}</p>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -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 {
|
||||
16
components/util/MiscStuff.tsx
Normal file
16
components/util/MiscStuff.tsx
Normal file
@@ -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 (
|
||||
<Tooltip {...props}>
|
||||
<TooltipTrigger asChild>
|
||||
{children}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="bg-surface0 text-text m-2">
|
||||
<span className="text-sm flex items-center">{text}</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
67
hooks/roblox/useAccountSettings.ts
Normal file
67
hooks/roblox/useAccountSettings.ts
Normal file
@@ -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<AccountSettings | false | null>(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;
|
||||
}
|
||||
63
hooks/roblox/useAvatarOutfits.ts
Normal file
63
hooks/roblox/useAvatarOutfits.ts
Normal file
@@ -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<Outfit[] | false | null>(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;
|
||||
}
|
||||
89
hooks/roblox/useBestFriends.ts
Normal file
89
hooks/roblox/useBestFriends.ts
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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();
|
||||
|
||||
@@ -14,7 +14,7 @@ export type AssetThumbnail = {
|
||||
};
|
||||
|
||||
export type ThumbnailRequest = {
|
||||
type: "GameThumbnail" | "AvatarHeadShot";
|
||||
type: "GameThumbnail" | "AvatarHeadShot" | "Outfit" | `${string}`;
|
||||
targetId: number;
|
||||
format: "webp";
|
||||
size: string;
|
||||
|
||||
@@ -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",
|
||||
|
||||
BIN
public/bg.png
Normal file
BIN
public/bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 632 KiB |
Reference in New Issue
Block a user