qol fix outfit switcher
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
// chatgpt
|
||||
function rewriteCookieDomain(rawCookie: string): string {
|
||||
return rawCookie
|
||||
.replace(/;?\s*Domain=[^;]+/i, '')
|
||||
.concat(`; Domain=localhost:3000`);
|
||||
}
|
||||
|
||||
// chatgpt
|
||||
async function proxyRequest(request: Request, method: string) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const target = searchParams.get("url");
|
||||
|
||||
if (!target) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Missing `url` query parameter." }),
|
||||
JSON.stringify({ error: "missing url param, dumbass" }),
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
@@ -16,7 +24,7 @@ async function proxyRequest(request: Request, method: string) {
|
||||
|
||||
const headers = new Headers(request.headers);
|
||||
headers.delete("host");
|
||||
headers.delete("accept-encoding"); // ! important
|
||||
headers.delete("accept-encoding");
|
||||
|
||||
const init: RequestInit = {
|
||||
method,
|
||||
@@ -30,8 +38,20 @@ async function proxyRequest(request: Request, method: string) {
|
||||
|
||||
const response = await fetch(targetUrl, init);
|
||||
|
||||
// Copy all response headers
|
||||
const responseHeaders = new Headers(response.headers);
|
||||
responseHeaders.delete("content-encoding"); // ! important
|
||||
responseHeaders.delete("content-encoding");
|
||||
|
||||
const rawSetCookies = response.headers.getSetCookie?.() ?? [];
|
||||
|
||||
if (rawSetCookies.length > 0) {
|
||||
responseHeaders.delete("set-cookie");
|
||||
|
||||
for (const rawCookie of rawSetCookies) {
|
||||
const rewritten = rewriteCookieDomain(rawCookie);
|
||||
responseHeaders.append("set-cookie", rewritten);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
|
||||
8
bun.lock
8
bun.lock
@@ -6,6 +6,7 @@
|
||||
"dependencies": {
|
||||
"@catppuccin/tailwindcss": "^0.1.6",
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@ocbwoy3/libocbwoy3": "^0.0.5",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
@@ -34,6 +35,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/bun": "^1.2.19",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -161,6 +163,8 @@
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@ocbwoy3/libocbwoy3": ["@ocbwoy3/libocbwoy3@0.0.5", "", {}, "sha512-zDm11Z5xzmOgsDg/E8Z9UFlMYjKdkUg28YE/Fwb0+NoVx5gKyj3D9eSbvBAOfTISTKkI3X2FTWHg3ehvyLz1Fg=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||
@@ -281,6 +285,8 @@
|
||||
|
||||
"@tailwindcss/line-clamp": ["@tailwindcss/line-clamp@0.4.4", "", { "peerDependencies": { "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, "sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||
|
||||
"@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="],
|
||||
|
||||
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
|
||||
@@ -345,6 +351,8 @@
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
||||
|
||||
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
|
||||
|
||||
"camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="],
|
||||
|
||||
@@ -12,6 +12,18 @@ import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
import { useFriendsPresence } from "@/hooks/roblox/usePresence";
|
||||
import { useAccountSettings } from "@/hooks/roblox/useAccountSettings";
|
||||
import { loadThumbnails } from "@/lib/thumbnailLoader";
|
||||
import { toast } from "sonner";
|
||||
|
||||
// chatgpt + human
|
||||
function randomGreeting(name: string): string {
|
||||
const greetings = [
|
||||
`Howdy, ${name}`
|
||||
];
|
||||
|
||||
const index = Math.floor(Math.random() * greetings.length);
|
||||
return greetings[index];
|
||||
}
|
||||
|
||||
export function HomeLoggedInHeader() {
|
||||
const profile = useCurrentAccount();
|
||||
@@ -52,7 +64,23 @@ export function HomeLoggedInHeader() {
|
||||
return (
|
||||
<>
|
||||
{/* <button onClick={()=>console.log(userPresence)}>debug this</button> */}
|
||||
<div className="flex items-center gap-6 rounded-xl px-8 py-6 w-fit mt-8 ml-0">
|
||||
<div
|
||||
className="flex items-center gap-6 rounded-xl px-8 py-6 w-fit mt-8 ml-0"
|
||||
onContextMenu={(e) => {
|
||||
if (e.button === 2) {
|
||||
toast("[debug] reloading user pfp");
|
||||
console.log("[debug] reloading user pfp");
|
||||
loadThumbnails([
|
||||
{
|
||||
type: "AvatarHeadShot",
|
||||
targetId: profile ? profile.id : 1,
|
||||
format: "webp",
|
||||
size: "720x720"
|
||||
}
|
||||
]).catch(() => {});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!isLoaded ? (
|
||||
<Skeleton className="w-28 h-28 rounded-full" />
|
||||
) : (
|
||||
@@ -64,14 +92,7 @@ export function HomeLoggedInHeader() {
|
||||
)}
|
||||
<div className="flex flex-col justify-center">
|
||||
<span className="text-3xl font-bold text-text flex items-center gap-2">
|
||||
{isLoaded ? (
|
||||
<>
|
||||
{!!accountSettings &&
|
||||
accountSettings.IsPremium === true
|
||||
? `Howdy, ${profile.displayName}`
|
||||
: `${profile.displayName}`}
|
||||
</>
|
||||
) : (
|
||||
{isLoaded ? randomGreeting(window.localStorage.UserPreferredName || profile.displayName || "Robloxian!") : (
|
||||
<>
|
||||
<Skeleton className="w-96 h-8 rounded-lg" />
|
||||
</>
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
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 { 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}) {
|
||||
async function updateOutfit(outfit: { id: number }, acc: { id: number }) {
|
||||
try {
|
||||
const J = (await (
|
||||
// ocbwoy3 stupid idiot for using v3 api
|
||||
const details = (await (
|
||||
await proxyFetch(
|
||||
`https://avatar.roblox.com/v1/outfits/${outfit.id}/details`
|
||||
)
|
||||
).json()) as {
|
||||
id: number;
|
||||
name: string;
|
||||
bodyColors: Record<string, string>;
|
||||
scale: Record<string, number>;
|
||||
};
|
||||
|
||||
const detailsV3 = (await (
|
||||
await proxyFetch(
|
||||
`https://avatar.roblox.com/v3/outfits/${outfit.id}/details`
|
||||
)
|
||||
@@ -26,16 +31,50 @@ async function updateOutfit(outfit: { id: number }, acc: {id: number}) {
|
||||
id: number;
|
||||
name: string;
|
||||
assets: any[];
|
||||
bodyColors: Record<string, string>;
|
||||
scale: Record<string, number>;
|
||||
playerAvatarType: "R6" | "R15";
|
||||
};
|
||||
|
||||
await proxyFetch(
|
||||
`https://avatar.roblox.com/v1/avatar/set-body-colors`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(details.bodyColors)
|
||||
}
|
||||
);
|
||||
|
||||
await proxyFetch(`https://avatar.roblox.com/v1/avatar/set-scales`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(details.scale)
|
||||
});
|
||||
|
||||
// u cant set avatar item scaling/rotation cuz roblox can't make good web apis
|
||||
await proxyFetch(
|
||||
`https://avatar.roblox.com/v1/avatar/set-wearing-assets`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
assetIds: J.assets.map(a=>a.id).filter(a=>!!a)
|
||||
assetIds: detailsV3.assets.map((a) => a.id).filter(Boolean)
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
await proxyFetch(
|
||||
`https://avatar.roblox.com/v1/avatar/set-player-avatar-type`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
playerAvatarType: detailsV3.playerAvatarType
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
loadThumbnails([
|
||||
{
|
||||
type: "AvatarHeadShot",
|
||||
@@ -43,25 +82,28 @@ async function updateOutfit(outfit: { id: number }, acc: {id: number}) {
|
||||
format: "webp",
|
||||
size: "720x720"
|
||||
}
|
||||
]).catch((a) => {});
|
||||
} catch {}
|
||||
]).catch(() => {});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const QuickTopUI = React.memo(function () {
|
||||
const robux = useRobuxBalance();
|
||||
const [isOutfitSelectorVisible, setIsOutfitSelectorVisible] =
|
||||
useState<boolean>(false);
|
||||
return (
|
||||
<>
|
||||
{/* {isOutfitSelectorVisible ? (
|
||||
<OutfitSelector setVisible={setIsOutfitSelectorVisible} updateOutfit={updateOutfit} />
|
||||
{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">
|
||||
<StupidHoverThing text="Change Outfit">
|
||||
<button
|
||||
className="rounded-full bg-crust/50 flex items-center p-2"
|
||||
onClick={() => {
|
||||
@@ -70,15 +112,21 @@ export const QuickTopUI = React.memo(function () {
|
||||
>
|
||||
<ShirtIcon />
|
||||
</button>
|
||||
</StupidHoverThing> */}
|
||||
</StupidHoverThing>
|
||||
|
||||
<StupidHoverThing
|
||||
text={!robux ? "Loading..." : `You have ${robux} Robux`}
|
||||
text={
|
||||
!robux
|
||||
? "You might probably have some Robux..."
|
||||
: `You have ${robux.toLocaleString()} 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>
|
||||
<p className="pl-1">
|
||||
{robux ? robux.toLocaleString() : "???"}
|
||||
</p>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
@@ -93,7 +141,9 @@ 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>
|
||||
<p className="mt-2">{"ocbwoy3-chan's roblox"}</p>
|
||||
<p className="mt-2 text-surface2 font-mono line-clamp-1">{process.env.NODE_ENV} {process.env.NEXT_PUBLIC_CWD} {process.env.NEXT_PUBLIC_ARGV0}</p>
|
||||
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
283
lib/robloxEngine/BrickColorIds.ts
Normal file
283
lib/robloxEngine/BrickColorIds.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
export const BrickColors: {
|
||||
name: string;
|
||||
id: number;
|
||||
col: [number, number, number];
|
||||
}[] = [
|
||||
{ name: "White", id: 1, col: [242, 243, 243] },
|
||||
{ name: "Grey", id: 2, col: [161, 165, 162] },
|
||||
{ name: "Light yellow", id: 3, col: [249, 233, 153] },
|
||||
{ name: "Brick yellow", id: 5, col: [215, 197, 154] },
|
||||
{ name: "Light green (Mint)", id: 6, col: [194, 218, 184] },
|
||||
{ name: "Light reddish violet", id: 9, col: [232, 186, 200] },
|
||||
{ name: "Pastel Blue", id: 11, col: [128, 187, 219] },
|
||||
{ name: "Light orange brown", id: 12, col: [203, 132, 66] },
|
||||
{ name: "Nougat", id: 18, col: [204, 142, 105] },
|
||||
{ name: "Bright red", id: 21, col: [196, 40, 28] },
|
||||
{ name: "Med. reddish violet", id: 22, col: [196, 112, 160] },
|
||||
{ name: "Bright blue", id: 23, col: [13, 105, 172] },
|
||||
{ name: "Bright yellow", id: 24, col: [245, 205, 48] },
|
||||
{ name: "Earth orange", id: 25, col: [98, 71, 50] },
|
||||
{ name: "Black", id: 26, col: [27, 42, 53] },
|
||||
{ name: "Dark grey", id: 27, col: [109, 110, 108] },
|
||||
{ name: "Dark green", id: 28, col: [40, 127, 71] },
|
||||
{ name: "Medium green", id: 29, col: [161, 196, 140] },
|
||||
{ name: "Lig. Yellowich orange", id: 36, col: [243, 207, 155] },
|
||||
{ name: "Bright green", id: 37, col: [75, 151, 75] },
|
||||
{ name: "Dark orange", id: 38, col: [160, 95, 53] },
|
||||
{ name: "Light bluish violet", id: 39, col: [193, 202, 222] },
|
||||
{ name: "Transparent", id: 40, col: [236, 236, 236] },
|
||||
{ name: "Tr. Red", id: 41, col: [205, 84, 75] },
|
||||
{ name: "Tr. Lg blue", id: 42, col: [193, 223, 240] },
|
||||
{ name: "Tr. Blue", id: 43, col: [123, 182, 232] },
|
||||
{ name: "Tr. Yellow", id: 44, col: [247, 241, 141] },
|
||||
{ name: "Light blue", id: 45, col: [180, 210, 228] },
|
||||
{ name: "Tr. Flu. Reddish orange", id: 47, col: [217, 133, 108] },
|
||||
{ name: "Tr. Green", id: 48, col: [132, 182, 141] },
|
||||
{ name: "Tr. Flu. Green", id: 49, col: [248, 241, 132] },
|
||||
{ name: "Phosph. White", id: 50, col: [236, 232, 222] },
|
||||
{ name: "Light red", id: 100, col: [238, 196, 182] },
|
||||
{ name: "Medium red", id: 101, col: [218, 134, 122] },
|
||||
{ name: "Medium blue", id: 102, col: [110, 153, 202] },
|
||||
{ name: "Light grey", id: 103, col: [199, 193, 183] },
|
||||
{ name: "Bright violet", id: 104, col: [107, 50, 124] },
|
||||
{ name: "Br. yellowish orange", id: 105, col: [226, 155, 64] },
|
||||
{ name: "Bright orange", id: 106, col: [218, 133, 65] },
|
||||
{ name: "Bright bluish green", id: 107, col: [0, 143, 156] },
|
||||
{ name: "Earth yellow", id: 108, col: [104, 92, 67] },
|
||||
{ name: "Bright bluish violet", id: 110, col: [67, 84, 147] },
|
||||
{ name: "Tr. Brown", id: 111, col: [191, 183, 177] },
|
||||
{ name: "Medium bluish violet", id: 112, col: [104, 116, 172] },
|
||||
{ name: "Tr. Medi. reddish violet", id: 113, col: [229, 173, 200] },
|
||||
{ name: "Med. yellowish green", id: 115, col: [199, 210, 60] },
|
||||
{ name: "Med. bluish green", id: 116, col: [85, 165, 175] },
|
||||
{ name: "Light bluish green", id: 118, col: [183, 215, 213] },
|
||||
{ name: "Br. yellowish green", id: 119, col: [164, 189, 71] },
|
||||
{ name: "Lig. yellowish green", id: 120, col: [217, 228, 167] },
|
||||
{ name: "Med. yellowish orange", id: 121, col: [231, 172, 88] },
|
||||
{ name: "Br. reddish orange", id: 123, col: [211, 111, 76] },
|
||||
{ name: "Bright reddish violet", id: 124, col: [146, 57, 120] },
|
||||
{ name: "Light orange", id: 125, col: [234, 184, 146] },
|
||||
{ name: "Tr. Bright bluish violet", id: 126, col: [165, 165, 203] },
|
||||
{ name: "Gold", id: 127, col: [220, 188, 129] },
|
||||
{ name: "Dark nougat", id: 128, col: [174, 122, 89] },
|
||||
{ name: "Silver", id: 131, col: [156, 163, 168] },
|
||||
{ name: "Neon orange", id: 133, col: [213, 115, 61] },
|
||||
{ name: "Neon green", id: 134, col: [216, 221, 86] },
|
||||
{ name: "Sand blue", id: 135, col: [116, 134, 157] },
|
||||
{ name: "Sand violet", id: 136, col: [135, 124, 144] },
|
||||
{ name: "Medium orange", id: 137, col: [224, 152, 100] },
|
||||
{ name: "Sand yellow", id: 138, col: [149, 138, 115] },
|
||||
{ name: "Earth blue", id: 140, col: [32, 58, 86] },
|
||||
{ name: "Earth green", id: 141, col: [39, 70, 45] },
|
||||
{ name: "Tr. Flu. Blue", id: 143, col: [207, 226, 247] },
|
||||
{ name: "Sand blue metallic", id: 145, col: [121, 136, 161] },
|
||||
{ name: "Sand violet metallic", id: 146, col: [149, 142, 163] },
|
||||
{ name: "Sand yellow metallic", id: 147, col: [147, 135, 103] },
|
||||
{ name: "Dark grey metallic", id: 148, col: [87, 88, 87] },
|
||||
{ name: "Black metallic", id: 149, col: [22, 29, 50] },
|
||||
{ name: "Light grey metallic", id: 150, col: [171, 173, 172] },
|
||||
{ name: "Sand green", id: 151, col: [120, 144, 130] },
|
||||
{ name: "Sand red", id: 153, col: [149, 121, 119] },
|
||||
{ name: "Dark red", id: 154, col: [123, 46, 47] },
|
||||
{ name: "Tr. Flu. Yellow", id: 157, col: [255, 246, 123] },
|
||||
{ name: "Tr. Flu. Red", id: 158, col: [225, 164, 194] },
|
||||
{ name: "Gun metallic", id: 168, col: [117, 108, 98] },
|
||||
{ name: "Red flip/flop", id: 176, col: [151, 105, 91] },
|
||||
{ name: "Yellow flip/flop", id: 178, col: [180, 132, 85] },
|
||||
{ name: "Silver flip/flop", id: 179, col: [137, 135, 136] },
|
||||
{ name: "Curry", id: 180, col: [215, 169, 75] },
|
||||
{ name: "Fire Yellow", id: 190, col: [249, 214, 46] },
|
||||
{ name: "Flame yellowish orange", id: 191, col: [232, 171, 45] },
|
||||
{ name: "Reddish brown", id: 192, col: [105, 64, 40] },
|
||||
{ name: "Flame reddish orange", id: 193, col: [207, 96, 36] },
|
||||
{ name: "Medium stone grey", id: 194, col: [163, 162, 165] },
|
||||
{ name: "Royal blue", id: 195, col: [70, 103, 164] },
|
||||
{ name: "Dark Royal blue", id: 196, col: [35, 71, 139] },
|
||||
{ name: "Bright reddish lilac", id: 198, col: [142, 66, 133] },
|
||||
{ name: "Dark stone grey", id: 199, col: [99, 95, 98] },
|
||||
{ name: "Lemon metalic", id: 200, col: [130, 138, 93] },
|
||||
{ name: "Light stone grey", id: 208, col: [229, 228, 223] },
|
||||
{ name: "Dark Curry", id: 209, col: [176, 142, 68] },
|
||||
{ name: "Faded green", id: 210, col: [112, 149, 120] },
|
||||
{ name: "Turquoise", id: 211, col: [121, 181, 181] },
|
||||
{ name: "Light Royal blue", id: 212, col: [159, 195, 233] },
|
||||
{ name: "Medium Royal blue", id: 213, col: [108, 129, 183] },
|
||||
{ name: "Rust", id: 216, col: [144, 76, 42] },
|
||||
{ name: "Brown", id: 217, col: [124, 92, 70] },
|
||||
{ name: "Reddish lilac", id: 218, col: [150, 112, 159] },
|
||||
{ name: "Lilac", id: 219, col: [107, 98, 155] },
|
||||
{ name: "Light lilac", id: 220, col: [167, 169, 206] },
|
||||
{ name: "Bright purple", id: 221, col: [205, 98, 152] },
|
||||
{ name: "Light purple", id: 222, col: [228, 173, 200] },
|
||||
{ name: "Light pink", id: 223, col: [220, 144, 149] },
|
||||
{ name: "Light brick yellow", id: 224, col: [240, 213, 160] },
|
||||
{ name: "Warm yellowish orange", id: 225, col: [235, 184, 127] },
|
||||
{ name: "Cool yellow", id: 226, col: [253, 234, 141] },
|
||||
{ name: "Dove blue", id: 232, col: [125, 187, 221] },
|
||||
{ name: "Medium lilac", id: 268, col: [52, 43, 117] },
|
||||
{ name: "Slime green", id: 301, col: [80, 109, 84] },
|
||||
{ name: "Smoky grey", id: 302, col: [91, 93, 105] },
|
||||
{ name: "Dark blue", id: 303, col: [0, 16, 176] },
|
||||
{ name: "Parsley green", id: 304, col: [44, 101, 29] },
|
||||
{ name: "Steel blue", id: 305, col: [82, 124, 174] },
|
||||
{ name: "Storm blue", id: 306, col: [51, 88, 130] },
|
||||
{ name: "Lapis", id: 307, col: [16, 42, 220] },
|
||||
{ name: "Dark indigo", id: 308, col: [61, 21, 133] },
|
||||
{ name: "Sea green", id: 309, col: [52, 142, 64] },
|
||||
{ name: "Shamrock", id: 310, col: [91, 154, 76] },
|
||||
{ name: "Fossil", id: 311, col: [159, 161, 172] },
|
||||
{ name: "Mulberry", id: 312, col: [89, 34, 89] },
|
||||
{ name: "Forest green", id: 313, col: [31, 128, 29] },
|
||||
{ name: "Cadet blue", id: 314, col: [159, 173, 192] },
|
||||
{ name: "Electric blue", id: 315, col: [9, 137, 207] },
|
||||
{ name: "Eggplant", id: 316, col: [123, 0, 123] },
|
||||
{ name: "Moss", id: 317, col: [124, 156, 107] },
|
||||
{ name: "Artichoke", id: 318, col: [138, 171, 133] },
|
||||
{ name: "Sage green", id: 319, col: [185, 196, 177] },
|
||||
{ name: "Ghost grey", id: 320, col: [202, 203, 209] },
|
||||
{ name: "Lilac", id: 321, col: [167, 94, 155] },
|
||||
{ name: "Plum", id: 322, col: [123, 47, 123] },
|
||||
{ name: "Olivine", id: 323, col: [148, 190, 129] },
|
||||
{ name: "Laurel green", id: 324, col: [168, 189, 153] },
|
||||
{ name: "Quill grey", id: 325, col: [223, 223, 222] },
|
||||
{ name: "Crimson", id: 327, col: [151, 0, 0] },
|
||||
{ name: "Mint", id: 328, col: [177, 229, 166] },
|
||||
{ name: "Baby blue", id: 329, col: [152, 194, 219] },
|
||||
{ name: "Carnation pink", id: 330, col: [255, 152, 220] },
|
||||
{ name: "Persimmon", id: 331, col: [255, 89, 89] },
|
||||
{ name: "Maroon", id: 332, col: [117, 0, 0] },
|
||||
{ name: "Gold", id: 333, col: [239, 184, 56] },
|
||||
{ name: "Daisy orange", id: 334, col: [248, 217, 109] },
|
||||
{ name: "Pearl", id: 335, col: [231, 231, 236] },
|
||||
{ name: "Fog", id: 336, col: [199, 212, 228] },
|
||||
{ name: "Salmon", id: 337, col: [255, 148, 148] },
|
||||
{ name: "Terra Cotta", id: 338, col: [190, 104, 98] },
|
||||
{ name: "Cocoa", id: 339, col: [86, 36, 36] },
|
||||
{ name: "Wheat", id: 340, col: [241, 231, 199] },
|
||||
{ name: "Buttermilk", id: 341, col: [254, 243, 187] },
|
||||
{ name: "Mauve", id: 342, col: [224, 178, 208] },
|
||||
{ name: "Sunrise", id: 343, col: [212, 144, 189] },
|
||||
{ name: "Tawny", id: 344, col: [150, 85, 85] },
|
||||
{ name: "Rust", id: 345, col: [143, 76, 42] },
|
||||
{ name: "Cashmere", id: 346, col: [211, 190, 150] },
|
||||
{ name: "Khaki", id: 347, col: [226, 220, 188] },
|
||||
{ name: "Lily white", id: 348, col: [237, 234, 234] },
|
||||
{ name: "Seashell", id: 349, col: [233, 218, 218] },
|
||||
{ name: "Burgundy", id: 350, col: [136, 62, 62] },
|
||||
{ name: "Cork", id: 351, col: [188, 155, 93] },
|
||||
{ name: "Burlap", id: 352, col: [199, 172, 120] },
|
||||
{ name: "Beige", id: 353, col: [202, 191, 163] },
|
||||
{ name: "Oyster", id: 354, col: [187, 179, 178] },
|
||||
{ name: "Pine Cone", id: 355, col: [108, 88, 75] },
|
||||
{ name: "Fawn brown", id: 356, col: [160, 132, 79] },
|
||||
{ name: "Hurricane grey", id: 357, col: [149, 137, 136] },
|
||||
{ name: "Cloudy grey", id: 358, col: [171, 168, 158] },
|
||||
{ name: "Linen", id: 359, col: [175, 148, 131] },
|
||||
{ name: "Copper", id: 360, col: [150, 103, 102] },
|
||||
{ name: "Medium brown", id: 361, col: [86, 66, 54] },
|
||||
{ name: "Bronze", id: 362, col: [126, 104, 63] },
|
||||
{ name: "Flint", id: 363, col: [105, 102, 92] },
|
||||
{ name: "Dark taupe", id: 364, col: [90, 76, 66] },
|
||||
{ name: "Burnt Sienna", id: 365, col: [106, 57, 9] },
|
||||
{ name: "Institutional white", id: 1001, col: [248, 248, 248] },
|
||||
{ name: "Mid gray", id: 1002, col: [205, 205, 205] },
|
||||
{ name: "Really black", id: 1003, col: [17, 17, 17] },
|
||||
{ name: "Really red", id: 1004, col: [255, 0, 0] },
|
||||
{ name: "Deep orange", id: 1005, col: [255, 176, 0] },
|
||||
{ name: "Alder", id: 1006, col: [180, 128, 255] },
|
||||
{ name: "Dusty Rose", id: 1007, col: [163, 75, 75] },
|
||||
{ name: "Olive", id: 1008, col: [193, 190, 66] },
|
||||
{ name: "New Yeller", id: 1009, col: [255, 255, 0] },
|
||||
{ name: "Really blue", id: 1010, col: [0, 0, 255] },
|
||||
{ name: "Navy blue", id: 1011, col: [0, 32, 96] },
|
||||
{ name: "Deep blue", id: 1012, col: [33, 84, 185] },
|
||||
{ name: "Cyan", id: 1013, col: [4, 175, 236] },
|
||||
{ name: "CGA brown", id: 1014, col: [170, 85, 0] },
|
||||
{ name: "Magenta", id: 1015, col: [170, 0, 170] },
|
||||
{ name: "Pink", id: 1016, col: [255, 102, 204] },
|
||||
{ name: "Deep orange", id: 1017, col: [255, 175, 0] },
|
||||
{ name: "Teal", id: 1018, col: [18, 238, 212] },
|
||||
{ name: "Toothpaste", id: 1019, col: [0, 255, 255] },
|
||||
{ name: "Lime green", id: 1020, col: [0, 255, 0] },
|
||||
{ name: "Camo", id: 1021, col: [58, 125, 21] },
|
||||
{ name: "Grime", id: 1022, col: [127, 142, 100] },
|
||||
{ name: "Lavender", id: 1023, col: [140, 91, 159] },
|
||||
{ name: "Pastel light blue", id: 1024, col: [175, 221, 255] },
|
||||
{ name: "Pastel orange", id: 1025, col: [255, 201, 201] },
|
||||
{ name: "Pastel violet", id: 1026, col: [177, 167, 255] },
|
||||
{ name: "Pastel blue-green", id: 1027, col: [159, 243, 233] },
|
||||
{ name: "Pastel green", id: 1028, col: [204, 255, 204] },
|
||||
{ name: "Pastel yellow", id: 1029, col: [255, 255, 204] },
|
||||
{ name: "Pastel brown", id: 1030, col: [255, 204, 153] },
|
||||
{ name: "Royal purple", id: 1031, col: [98, 37, 209] },
|
||||
{ name: "Hot pink", id: 1032, col: [255, 0, 191] }
|
||||
];
|
||||
|
||||
// chatgpt
|
||||
export const BrickColorHexMap: { [hex: string]: number } = Object.fromEntries(
|
||||
BrickColors.map(({ id, col }) => {
|
||||
const hex = rgbToHex(...col);
|
||||
return [hex, id];
|
||||
})
|
||||
);
|
||||
|
||||
// chatgpt
|
||||
function rgbToHex(r: number, g: number, b: number): string {
|
||||
return [r, g, b]
|
||||
.map((v) => {
|
||||
const hex = Math.round(v).toString(16).padStart(2, "0");
|
||||
return hex;
|
||||
})
|
||||
.join("")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* find the closest roblox brickcolor id of a hex color
|
||||
* made by chatgpt
|
||||
*/
|
||||
export function findClosestBrickColor(hex: string): {
|
||||
id: number;
|
||||
name: string;
|
||||
col: [number, number, number];
|
||||
} {
|
||||
const target = hexToRgb(hex);
|
||||
console.log(hex,target)
|
||||
if (!target) throw new Error("Invalid hex");
|
||||
|
||||
let bestDist = Infinity;
|
||||
let bestColor = BrickColors[0];
|
||||
|
||||
for (const brick of BrickColors) {
|
||||
const [r, g, b] = brick.col;
|
||||
const dist = euclideanDistance(target, [r, g, b]);
|
||||
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
bestColor = brick;
|
||||
}
|
||||
}
|
||||
|
||||
return bestColor;
|
||||
}
|
||||
|
||||
// chatgpt
|
||||
function hexToRgb(hex?: string): [number, number, number] | null {
|
||||
if (typeof hex !== "string") return null;
|
||||
|
||||
const cleaned = hex.replace(/^#/, "").toLowerCase();
|
||||
if (!/^[0-9a-f]{6}$/.test(cleaned)) return null;
|
||||
|
||||
const r = parseInt(cleaned.slice(0, 2), 16);
|
||||
const g = parseInt(cleaned.slice(2, 4), 16);
|
||||
const b = parseInt(cleaned.slice(4, 6), 16);
|
||||
return [r, g, b];
|
||||
}
|
||||
|
||||
// chatgpt
|
||||
function euclideanDistance(
|
||||
a: [number, number, number],
|
||||
b: [number, number, number]
|
||||
) {
|
||||
return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2;
|
||||
}
|
||||
39
lib/utils.ts
39
lib/utils.ts
@@ -7,7 +7,7 @@ export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export async function proxyFetch(
|
||||
export async function proxyFetchRaw(
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit
|
||||
): Promise<Response> {
|
||||
@@ -17,18 +17,49 @@ export async function proxyFetch(
|
||||
: input instanceof Request
|
||||
? input.url
|
||||
: "";
|
||||
|
||||
const proxyUrl = `/api/proxy?url=${encodeURIComponent(url)}`;
|
||||
|
||||
// fix headers
|
||||
// Fix headers
|
||||
const headers = new Headers(init?.headers || {});
|
||||
headers.delete("accept-encoding"); // prevent stupid encoding bug
|
||||
headers.delete("accept-encoding"); // prevent encoding issues
|
||||
|
||||
const fetchInit: RequestInit = {
|
||||
...init,
|
||||
method: init?.method || "GET",
|
||||
headers,
|
||||
body: init?.body
|
||||
body: init?.body,
|
||||
};
|
||||
|
||||
return window.fetch(proxyUrl, fetchInit);
|
||||
}
|
||||
|
||||
// CSRF-aware proxy fetch
|
||||
export async function proxyFetch(
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit
|
||||
): Promise<Response> {
|
||||
const xsrfRequestMethods = ["POST", "PATCH", "DELETE"];
|
||||
const csrfTokenHeader = "x-csrf-token";
|
||||
const csrfInvalidResponseCode = 403;
|
||||
|
||||
const method = init?.method?.toUpperCase() || "GET";
|
||||
|
||||
let response = await proxyFetchRaw(input, init);
|
||||
|
||||
if (
|
||||
xsrfRequestMethods.includes(method) &&
|
||||
response.status === csrfInvalidResponseCode &&
|
||||
response.headers.has(csrfTokenHeader)
|
||||
) {
|
||||
const newHeaders = new Headers(init?.headers || {});
|
||||
newHeaders.set(csrfTokenHeader, response.headers.get(csrfTokenHeader)!);
|
||||
|
||||
response = await proxyFetchRaw(input, {
|
||||
...init,
|
||||
headers: newHeaders,
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
if (!process.isBun) {
|
||||
console.error(`You are running this with node. Rerun the process: bun --bun run dev`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
process.env.NEXT_PUBLIC_CWD = __dirname || "~"
|
||||
process.env.NEXT_PUBLIC_ARGV0 = process.argv0 || "node"
|
||||
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
images: {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@catppuccin/tailwindcss": "^0.1.6",
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@ocbwoy3/libocbwoy3": "^0.0.5",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
@@ -39,6 +40,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/bun": "^1.2.19",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
|
||||
Reference in New Issue
Block a user