Add basic structure for a collaborative pixel art website
Adds the core project structure, including configuration files, a basic HTML page, and the main application component. It also lays the groundwork for the canvas, color palette, and configuration modal functionalities. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 0385ea33-cde8-4bbd-8fce-8d192d30eb41 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/870d08ce-da3b-4822-9874-c2fe2b7628b1/0385ea33-cde8-4bbd-8fce-8d192d30eb41/Vuy7IOw
This commit is contained in:
33
client/src/lib/config.ts
Normal file
33
client/src/lib/config.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export const COLORS = [
|
||||
"#FF0000", // Red
|
||||
"#FFA500", // Orange
|
||||
"#FFFF00", // Yellow
|
||||
"#00FF00", // Green
|
||||
"#0000FF", // Blue
|
||||
"#800080", // Purple
|
||||
"#FFC0CB", // Pink
|
||||
"#A52A2A", // Brown
|
||||
"#000000", // Black
|
||||
"#404040", // Dark Gray
|
||||
"#808080", // Gray
|
||||
"#C0C0C0", // Light Gray
|
||||
"#FFFFFF", // White
|
||||
"#00FFFF", // Cyan
|
||||
"#00FF80", // Lime
|
||||
"#4B0082", // Indigo
|
||||
] as const;
|
||||
|
||||
export const DEFAULT_SELECTED_COLOR = "#FF0000";
|
||||
|
||||
export function generateUserId(): string {
|
||||
const stored = localStorage.getItem("r-place-user-id");
|
||||
if (stored) return stored;
|
||||
|
||||
const newId = `User#${Math.floor(Math.random() * 10000)}`;
|
||||
localStorage.setItem("r-place-user-id", newId);
|
||||
return newId;
|
||||
}
|
||||
|
||||
export function getUsername(): string {
|
||||
return generateUserId();
|
||||
}
|
||||
57
client/src/lib/queryClient.ts
Normal file
57
client/src/lib/queryClient.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { QueryClient, QueryFunction } from "@tanstack/react-query";
|
||||
|
||||
async function throwIfResNotOk(res: Response) {
|
||||
if (!res.ok) {
|
||||
const text = (await res.text()) || res.statusText;
|
||||
throw new Error(`${res.status}: ${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiRequest(
|
||||
method: string,
|
||||
url: string,
|
||||
data?: unknown | undefined,
|
||||
): Promise<Response> {
|
||||
const res = await fetch(url, {
|
||||
method,
|
||||
headers: data ? { "Content-Type": "application/json" } : {},
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
await throwIfResNotOk(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
type UnauthorizedBehavior = "returnNull" | "throw";
|
||||
export const getQueryFn: <T>(options: {
|
||||
on401: UnauthorizedBehavior;
|
||||
}) => QueryFunction<T> =
|
||||
({ on401: unauthorizedBehavior }) =>
|
||||
async ({ queryKey }) => {
|
||||
const res = await fetch(queryKey.join("/") as string, {
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (unauthorizedBehavior === "returnNull" && res.status === 401) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await throwIfResNotOk(res);
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
queryFn: getQueryFn({ on401: "throw" }),
|
||||
refetchInterval: false,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: Infinity,
|
||||
retry: false,
|
||||
},
|
||||
mutations: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
6
client/src/lib/utils.ts
Normal file
6
client/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
Reference in New Issue
Block a user