ditch js client

This commit is contained in:
Adam 2024-12-03 17:52:45 -05:00
parent a4fb228f32
commit 3209aa6de0
78 changed files with 4 additions and 3840 deletions

View file

@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["server", "clients/leptos", "lib", "tools/socket_blaster"]
members = ["server", "client", "lib", "tools/socket_blaster"]
default-members = ["server", "lib"]
[workspace.dependencies]

View file

@ -3,7 +3,7 @@
#
[build]
target = "clients/leptos/index.html"
target = "client/index.html"
dist = "dist"
minify = "on_release"

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 685 B

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,2 +0,0 @@
node_modules
dist

View file

@ -1,34 +0,0 @@
## Usage
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
```bash
$ npm install # or pnpm install or yarn install
```
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
## Available Scripts
In the project directory, you can run:
### `npm run dev` or `npm start`
Runs the app in the development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
### `npm run build`
Builds the app for production to the `dist` folder.<br>
It correctly bundles Solid in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!
## Deployment
You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)

View file

@ -1,16 +0,0 @@
{
"$schema": "https://shadcn-solid.com/schema.json",
"tailwind": {
"config": "tailwind.config.ts",
"css": {
"path": "src/index.css",
"variable": true
},
"color": "neutral",
"prefix": ""
},
"alias": {
"component": "@/components",
"cn": "@/libs/cn"
}
}

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Cards for Humanity</title>
<style>
/* hax */
@media (prefers-color-scheme: dark) {
body, html {
background-color: #0a0a0a;
}
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

View file

@ -1,35 +0,0 @@
{
"name": "Cards for Humanity",
"type": "module",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"license": "MIT",
"devDependencies": {
"@types/node": "^22.9.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"solid-devtools": "^0.29.3",
"tailwindcss": "^3.4.15",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vite-plugin-solid": "^2.10.2"
},
"dependencies": {
"@corvu/drawer": "^0.2.2",
"@corvu/tailwind": "^0.1.5",
"@kobalte/core": "^0.13.7",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"corvu": "^0.7.1",
"joi": "^17.13.3",
"solid-js": "^1.9.3",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7"
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
module.exports = {
purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1 +0,0 @@
{"name":"Cards for Humanity","short_name":"C4H","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View file

@ -1,54 +0,0 @@
import type { JSXElement } from "solid-js";
import { lazy } from "solid-js";
import { ColorModeProvider, ColorModeScript } from "@kobalte/core";
import {
Tabs,
TabsContent,
TabsIndicator,
TabsList,
TabsTrigger,
} from "@/components/ui/tabs";
import Home from "@/pages/Home";
import Footer from "@/components/Footer";
import { Websocket, WebsocketProvider } from "./components/Websocket";
const Browser = lazy(() => import("@/pages/Browser"));
const Game = lazy(() => import("@/pages/Game"));
export default function App(): JSXElement {
return (
<>
<ColorModeScript />
<ColorModeProvider>
<WebsocketProvider>
<div class="lg:container m-auto relative">
<div class="transition-all p-1 lg:p-5 lg:rounded-2xl lg:shadow-xl min-h-screen lg:min-h-0 dark:bg-black">
<h1 class="text-4xl sm:text-6xl md:text-7xl lg:text-8xl tracking-tighter">
Cards For Humanity
</h1>
<br />
<Tabs defaultValue="home">
<TabsList>
<TabsTrigger value="home">Home</TabsTrigger>
<TabsTrigger value="browser">Browser</TabsTrigger>
<TabsTrigger value="game">Game</TabsTrigger>
<TabsIndicator variant="underline" />
</TabsList>
<TabsContent value="home">
<Home />
</TabsContent>
<TabsContent value="browser">
<Browser />
</TabsContent>
<TabsContent value="game">
<Game />
</TabsContent>
</Tabs>
<Footer />
</div>
</div>
</WebsocketProvider>
</ColorModeProvider>
</>
);
}

View file

@ -1,5 +0,0 @@
import { JSXElement } from "solid-js";
export function Chat(): JSXElement {
return <>chat</>;
}

View file

@ -1,38 +0,0 @@
import { createEffect, createSignal, JSXElement, useContext } from "solid-js";
import { Button } from "@/components/ui/button";
import { useWebsocket, WebsocketContext, WebsocketProvider } from "./Websocket";
export function Debug(): JSXElement {
const connected = useWebsocket;
// const [connected, set_connected] = createSignal(false);
const [user_count, _set_user_count] = createSignal("0");
const [game_count, _set_game_count] = createSignal("0");
// const toggle = () => set_connected(!connected());
createEffect(() => console.log(connected()));
return (
<div class="my-2 w-auto">
<h2 class="p-1 text-2xl">Debug:</h2>
<p class="p-1">
Connection Status: {connected() ? "Connected" : "Disconnected"}
</p>
<p class="p-1">Users Online: {user_count()}</p>
<p class="p-1">Active Games: {game_count()}</p>
<div class="p-1">
<Button
onClick={() => set_connected(!connected())}
disabled={connected()}
>
"Connect"
</Button>
<Button
onClick={() => set_connected(!connected())}
disabled={!connected()}
>
"Disconnect"
</Button>
</div>
</div>
);
}

View file

@ -1,58 +0,0 @@
import { JSXElement } from "solid-js";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerLabel,
DrawerTrigger,
} from "@/components/ui/drawer";
import { Chat } from "@/components/Chat";
import { Debug } from "@/components/Debug";
import { Separator } from "@/components/ui/separator";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
export default function Footer(): JSXElement {
return (
<>
<br />
<br />
<div class="transition-all fixed lg:static bottom-0 left-0 w-full lg:w-auto shadow-inner lg:shadow-none dark:bg-black">
<Separator />
<div class="flex justify-between">
<Popover>
<PopoverTrigger>Debug</PopoverTrigger>
<PopoverContent>
<Debug />
</PopoverContent>
</Popover>
<div class="m-2">
<a
class="p-2"
href="https://git.doordesk.net/adam/cards/"
target="_blank"
>
About
</a>
<a class="p-2" href="mailto:adam@doordesk.net">
Contact
</a>
</div>
<Drawer>
<DrawerTrigger>Chat</DrawerTrigger>
<DrawerContent>
<DrawerLabel>Chat</DrawerLabel>
<Chat />
</DrawerContent>
</Drawer>
</div>
</div>
</>
);
}

View file

@ -1,149 +0,0 @@
import Joi from "joi";
import {
createEffect,
createSignal,
onCleanup,
createContext,
useContext,
} from "solid-js";
export const WebsocketContext = createContext();
export function WebsocketProvider(props) {
const socket = new WebSocket("ws://127.0.0.1:3030/websocket");
// Signals
let [active_games, set_active_games] = createSignal(null);
let [card_packs_meta, set_card_packs_meta] = createSignal(null);
let [chat_message, set_chat_message] = createSignal(null);
let [chat_update, set_chat_update] = createSignal(null);
let [connected, set_connected] = createSignal(false);
let [game_meta, set_game_meta] = createSignal(null);
let [game_state, set_game_state] = createSignal(null);
let [games_count, set_games_count] = createSignal(null);
let [judge_round, set_judge_round] = createSignal(null);
let [user_update, set_user_update] = createSignal(null);
let [users_count, set_users_count] = createSignal(null);
// Wipe everything on disconnect
createEffect(() => {
if (!connected()) {
set_active_games(null);
set_card_packs_meta(null);
set_chat_message(null);
set_chat_update(null);
set_game_meta(null);
set_game_state(null);
set_games_count(null);
set_judge_round(null);
set_user_update(null);
set_users_count(null);
}
});
const state = [connected];
// Incoming message types
const UserUpdate = Joi.object({
username: Joi.string(),
});
const ChatMessage = Joi.object({
text: Joi.string(),
});
const ServerOnlineUsers = Joi.object({
online_users: Joi.number(),
});
const ServerActiveGames = Joi.object({
active_games: Joi.number(),
});
const ChatUpdate = Joi.object({
room: Joi.string(),
users: Joi.number(),
});
const GamesUpdate = Joi.object({
games: Joi.array(),
});
const CardPacksMeta = Joi.object({
official_meta: Joi.array(),
unofficial_meta: Joi.array(),
});
// Message handler
const handleMessage = (event: MessageEvent) => {
let json = JSON.parse(event.data);
// TODO: This is ridiculous but it works
try {
Joi.attempt(json, UserUpdate);
console.log("UserUpdate! Name is: ", json);
} catch {}
try {
Joi.attempt(json, ChatMessage);
console.log("Chat Message: ", json);
} catch {}
try {
Joi.attempt(json, ServerOnlineUsers);
console.log("Online Users: ", json);
} catch {}
try {
Joi.attempt(json, ServerActiveGames);
console.log("Active Games: ", json);
} catch {}
try {
Joi.attempt(json, ChatUpdate);
console.log("Chat Update: ", json);
} catch {}
try {
Joi.attempt(json, GamesUpdate);
console.log("GamesUpdate: ", json);
} catch {}
try {
Joi.attempt(json, CardPacksMeta);
console.log("Card Packs: ", json);
} catch {}
};
socket.addEventListener("message", handleMessage);
// Close handler
const handleClose = (event: CloseEvent) => {
set_connected(false);
console.log("Disconnected from websocket", event.code, event.reason);
};
socket.addEventListener("close", handleClose);
// Open handler
const handleOpen = () => {
set_connected(true);
console.log("Connected to websocket");
};
socket.addEventListener("open", handleOpen);
// Cleanup
onCleanup(() => {
socket.removeEventListener("message", handleMessage);
socket.removeEventListener("close", handleClose);
socket.close();
});
return (
<WebsocketContext.Provider value={state}>
{props.children}
</WebsocketContext.Provider>
);
}
export function useWebsocket() {
return useContext(WebsocketContext);
}

View file

@ -1,66 +0,0 @@
import { cn } from "@/libs/cn";
import type { ButtonRootProps } from "@kobalte/core/button";
import { Button as ButtonPrimitive } from "@kobalte/core/button";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import type { ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
export const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-[color,background-color,box-shadow] focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
type buttonProps<T extends ValidComponent = "button"> = ButtonRootProps<T> &
VariantProps<typeof buttonVariants> & {
class?: string;
};
export const Button = <T extends ValidComponent = "button">(
props: PolymorphicProps<T, buttonProps<T>>,
) => {
const [local, rest] = splitProps(props as buttonProps, [
"class",
"variant",
"size",
]);
return (
<ButtonPrimitive
class={cn(
buttonVariants({
size: local.size,
variant: local.variant,
}),
local.class,
)}
{...rest}
/>
);
};

View file

@ -1,128 +0,0 @@
import { cn } from "@/libs/cn";
import type {
DialogContentProps,
DialogDescriptionProps,
DialogTitleProps,
} from "@kobalte/core/dialog";
import { Dialog as DialogPrimitive } from "@kobalte/core/dialog";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type { ComponentProps, ParentProps, ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
export const Dialog = DialogPrimitive;
export const DialogTrigger = DialogPrimitive.Trigger;
type dialogContentProps<T extends ValidComponent = "div"> = ParentProps<
DialogContentProps<T> & {
class?: string;
}
>;
export const DialogContent = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, dialogContentProps<T>>,
) => {
const [local, rest] = splitProps(props as dialogContentProps, [
"class",
"children",
]);
return (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay
class={cn(
"fixed inset-0 z-50 bg-background/80 data-[expanded]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0",
)}
{...rest}
/>
<DialogPrimitive.Content
class={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg data-[closed]:duration-200 data-[expanded]:duration-200 data-[expanded]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0 data-[closed]:zoom-out-95 data-[expanded]:zoom-in-95 data-[closed]:slide-out-to-left-1/2 data-[closed]:slide-out-to-top-[48%] data-[expanded]:slide-in-from-left-1/2 data-[expanded]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
local.class,
)}
{...rest}
>
{local.children}
<DialogPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-[opacity,box-shadow] hover:opacity-100 focus:outline-none focus:ring-[1.5px] focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="h-4 w-4"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 6L6 18M6 6l12 12"
/>
<title>Close</title>
</svg>
</DialogPrimitive.CloseButton>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
);
};
type dialogTitleProps<T extends ValidComponent = "h2"> = DialogTitleProps<T> & {
class?: string;
};
export const DialogTitle = <T extends ValidComponent = "h2">(
props: PolymorphicProps<T, dialogTitleProps<T>>,
) => {
const [local, rest] = splitProps(props as dialogTitleProps, ["class"]);
return (
<DialogPrimitive.Title
class={cn("text-lg font-semibold text-foreground", local.class)}
{...rest}
/>
);
};
type dialogDescriptionProps<T extends ValidComponent = "p"> =
DialogDescriptionProps<T> & {
class?: string;
};
export const DialogDescription = <T extends ValidComponent = "p">(
props: PolymorphicProps<T, dialogDescriptionProps<T>>,
) => {
const [local, rest] = splitProps(props as dialogDescriptionProps, ["class"]);
return (
<DialogPrimitive.Description
class={cn("text-sm text-muted-foreground", local.class)}
{...rest}
/>
);
};
export const DialogHeader = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div
class={cn(
"flex flex-col space-y-2 text-center sm:text-left",
local.class,
)}
{...rest}
/>
);
};
export const DialogFooter = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div
class={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
local.class,
)}
{...rest}
/>
);
};

View file

@ -1,107 +0,0 @@
import { cn } from "@/libs/cn";
import type {
ContentProps,
DescriptionProps,
DynamicProps,
LabelProps,
} from "@corvu/drawer";
import DrawerPrimitive from "@corvu/drawer";
import type { ComponentProps, ParentProps, ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
export const Drawer = DrawerPrimitive;
export const DrawerTrigger = DrawerPrimitive.Trigger;
export const DrawerClose = DrawerPrimitive.Close;
type drawerContentProps<T extends ValidComponent = "div"> = ParentProps<
ContentProps<T> & {
class?: string;
}
>;
export const DrawerContent = <T extends ValidComponent = "div">(
props: DynamicProps<T, drawerContentProps<T>>,
) => {
const [local, rest] = splitProps(props as drawerContentProps, [
"class",
"children",
]);
const ctx = DrawerPrimitive.useContext();
return (
<DrawerPrimitive.Portal>
<DrawerPrimitive.Overlay
class="fixed inset-0 z-50 data-[transitioning]:transition-colors data-[transitioning]:duration-200"
style={{
"background-color": `hsl(var(--background) / ${0.8 * ctx.openPercentage()})`,
}}
/>
<DrawerPrimitive.Content
class={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-xl border bg-background after:absolute after:inset-x-0 after:top-full after:h-[50%] after:bg-inherit data-[transitioning]:transition-transform data-[transitioning]:duration-200 md:select-none",
local.class,
)}
{...rest}
>
<div class="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{local.children}
</DrawerPrimitive.Content>
</DrawerPrimitive.Portal>
);
};
export const DrawerHeader = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div
class={cn("grid gap-1.5 p-4 text-center sm:text-left", local.class)}
{...rest}
/>
);
};
export const DrawerFooter = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div class={cn("mt-auto flex flex-col gap-2 p-4", local.class)} {...rest} />
);
};
type DrawerLabelProps = LabelProps & {
class?: string;
};
export const DrawerLabel = <T extends ValidComponent = "h2">(
props: DynamicProps<T, DrawerLabelProps>,
) => {
const [local, rest] = splitProps(props as DrawerLabelProps, ["class"]);
return (
<DrawerPrimitive.Label
class={cn(
"text-lg font-semibold leading-none tracking-tight",
local.class,
)}
{...rest}
/>
);
};
type DrawerDescriptionProps = DescriptionProps & {
class?: string;
};
export const DrawerDescription = <T extends ValidComponent = "p">(
props: DynamicProps<T, DrawerDescriptionProps>,
) => {
const [local, rest] = splitProps(props as DrawerDescriptionProps, ["class"]);
return (
<DrawerPrimitive.Description
class={cn("text-sm text-muted-foreground", local.class)}
{...rest}
/>
);
};

View file

@ -1,65 +0,0 @@
import { cn } from "@/libs/cn";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type {
PopoverContentProps,
PopoverRootProps,
} from "@kobalte/core/popover";
import { Popover as PopoverPrimitive } from "@kobalte/core/popover";
import type { ParentProps, ValidComponent } from "solid-js";
import { mergeProps, splitProps } from "solid-js";
export const PopoverTrigger = PopoverPrimitive.Trigger;
export const PopoverTitle = PopoverPrimitive.Title;
export const PopoverDescription = PopoverPrimitive.Description;
export const Popover = (props: PopoverRootProps) => {
const merge = mergeProps<PopoverRootProps[]>({ gutter: 4 }, props);
return <PopoverPrimitive {...merge} />;
};
type popoverContentProps<T extends ValidComponent = "div"> = ParentProps<
PopoverContentProps<T> & {
class?: string;
}
>;
export const PopoverContent = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, popoverContentProps<T>>,
) => {
const [local, rest] = splitProps(props as popoverContentProps, [
"class",
"children",
]);
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
class={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[expanded]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0 data-[closed]:zoom-out-95 data-[expanded]:zoom-in-95",
local.class,
)}
{...rest}
>
{local.children}
<PopoverPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-[opacity,box-shadow] hover:opacity-100 focus:outline-none focus:ring-[1.5px] focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="h-4 w-4"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 6L6 18M6 6l12 12"
/>
<title>Close</title>
</svg>
</PopoverPrimitive.CloseButton>
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
);
};

View file

@ -1,26 +0,0 @@
import { cn } from "@/libs/cn";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type { SeparatorRootProps } from "@kobalte/core/separator";
import { Separator as SeparatorPrimitive } from "@kobalte/core/separator";
import type { ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
type separatorProps<T extends ValidComponent = "hr"> = SeparatorRootProps<T> & {
class?: string;
};
export const Separator = <T extends ValidComponent = "hr">(
props: PolymorphicProps<T, separatorProps<T>>,
) => {
const [local, rest] = splitProps(props as separatorProps, ["class"]);
return (
<SeparatorPrimitive
class={cn(
"shrink-0 bg-border data-[orientation=horizontal]:h-[1px] data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-[1px]",
local.class,
)}
{...rest}
/>
);
};

View file

@ -1,133 +0,0 @@
import { cn } from "@/libs/cn";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import type {
TabsContentProps,
TabsIndicatorProps,
TabsListProps,
TabsRootProps,
TabsTriggerProps,
} from "@kobalte/core/tabs";
import { Tabs as TabsPrimitive } from "@kobalte/core/tabs";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
import type { ValidComponent, VoidProps } from "solid-js";
import { splitProps } from "solid-js";
type tabsProps<T extends ValidComponent = "div"> = TabsRootProps<T> & {
class?: string;
};
export const Tabs = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, tabsProps<T>>,
) => {
const [local, rest] = splitProps(props as tabsProps, ["class"]);
return (
<TabsPrimitive
class={cn("w-full data-[orientation=vertical]:flex", local.class)}
{...rest}
/>
);
};
type tabsListProps<T extends ValidComponent = "div"> = TabsListProps<T> & {
class?: string;
};
export const TabsList = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, tabsListProps<T>>,
) => {
const [local, rest] = splitProps(props as tabsListProps, ["class"]);
return (
<TabsPrimitive.List
class={cn(
"relative flex w-full rounded-lg bg-muted p-1 text-muted-foreground data-[orientation=vertical]:flex-col data-[orientation=horizontal]:items-center data-[orientation=vertical]:items-stretch",
local.class,
)}
{...rest}
/>
);
};
type tabsContentProps<T extends ValidComponent = "div"> =
TabsContentProps<T> & {
class?: string;
};
export const TabsContent = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, tabsContentProps<T>>,
) => {
const [local, rest] = splitProps(props as tabsContentProps, ["class"]);
return (
<TabsPrimitive.Content
class={cn(
"transition-shadow duration-200 focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[orientation=horizontal]:mt-2 data-[orientation=vertical]:ml-2",
local.class,
)}
{...rest}
/>
);
};
type tabsTriggerProps<T extends ValidComponent = "button"> =
TabsTriggerProps<T> & {
class?: string;
};
export const TabsTrigger = <T extends ValidComponent = "button">(
props: PolymorphicProps<T, tabsTriggerProps<T>>,
) => {
const [local, rest] = splitProps(props as tabsTriggerProps, ["class"]);
return (
<TabsPrimitive.Trigger
class={cn(
"peer relative z-10 inline-flex h-7 w-full items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium outline-none transition-colors disabled:pointer-events-none disabled:opacity-50 data-[selected]:text-foreground",
local.class,
)}
{...rest}
/>
);
};
const tabsIndicatorVariants = cva(
"absolute transition-all duration-200 outline-none",
{
variants: {
variant: {
block:
"data-[orientation=horizontal]:bottom-1 data-[orientation=horizontal]:left-0 data-[orientation=vertical]:right-1 data-[orientation=vertical]:top-0 data-[orientation=horizontal]:h-[calc(100%-0.5rem)] data-[orientation=vertical]:w-[calc(100%-0.5rem)] bg-background shadow rounded-md peer-focus-visible:ring-[1.5px] peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background peer-focus-visible:outline-none",
underline:
"data-[orientation=horizontal]:-bottom-[1px] data-[orientation=horizontal]:left-0 data-[orientation=vertical]:-right-[1px] data-[orientation=vertical]:top-0 data-[orientation=horizontal]:h-[2px] data-[orientation=vertical]:w-[2px] bg-primary",
},
},
defaultVariants: {
variant: "block",
},
},
);
type tabsIndicatorProps<T extends ValidComponent = "div"> = VoidProps<
TabsIndicatorProps<T> &
VariantProps<typeof tabsIndicatorVariants> & {
class?: string;
}
>;
export const TabsIndicator = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, tabsIndicatorProps<T>>,
) => {
const [local, rest] = splitProps(props as tabsIndicatorProps, [
"class",
"variant",
]);
return (
<TabsPrimitive.Indicator
class={cn(tabsIndicatorVariants({ variant: local.variant }), local.class)}
{...rest}
/>
);
};

View file

@ -1,158 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* cyrillic-ext */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-greek-ext.woff2") format("woff2");
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-greek.woff2") format("woff2");
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1,
U+03A3-03FF;
}
/* vietnamese */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-vietnamese.woff2") format("woff2");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("/fonts/Inter-normal-400-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--radius: 0.5rem;
}
[data-kb-theme="dark"] {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
html,
body {
font-family: "Inter", "Arial", sans-serif;
}

View file

@ -1,14 +0,0 @@
/* @refresh reload */
import "./index.css";
import { render } from "solid-js/web";
import App from "./App";
const root = document.getElementById("root");
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
"Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
);
}
render(() => <App />, root!);

View file

@ -1,5 +0,0 @@
import type { ClassValue } from "clsx";
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
export const cn = (...classLists: ClassValue[]) => twMerge(clsx(classLists));

View file

@ -1,9 +0,0 @@
import type { JSXElement } from "solid-js";
export default function Browser(): JSXElement {
return (
<>
browser
</>
);
}

View file

@ -1,5 +0,0 @@
import type { JSXElement } from "solid-js";
export default function Game(): JSXElement {
return <>game</>;
}

View file

@ -1,28 +0,0 @@
import { Button } from "@/components/ui/button";
import type { JSXElement } from "solid-js";
export default function Home(): JSXElement {
return (
<>
<div class="p-4">
<h2 class="text-2xl">Hey!</h2>
<p class="indent-4 text-pretty my-3">
{
"Welcome! Thank you for helping me test this. Please let me know about any issues you may come across. Chances are you already know how to contact me but in case you don't you can email me at "
}
<a class="link link-info" href="mailto:adam@doordesk.net">
adam@doordesk.net
</a>
{
". The server may go down from time to time as bugs are found and as I add updates. If you manage to crash the server or notice it down for a long time please tell me about it."
}
</p>
<p>Have fun!</p>
</div>
<div class="my-5 flex flex-wrap justify-around">
<Button>Find a Game</Button>
<Button>Create a Game</Button>
</div>
</>
);
}

View file

@ -1,93 +0,0 @@
import type { Config } from "tailwindcss";
const config: Config = {
darkMode: ["class", '[data-kb-theme="dark"]'],
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,css,md,mdx,html,json,scss}",
],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--kb-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--kb-accordion-content-height)" },
to: { height: "0" },
},
"collapsible-down": {
from: { height: "0" },
to: { height: "var(--kb-collapsible-content-height)" },
},
"collapsible-up": {
from: { height: "var(--kb-collapsible-content-height)" },
to: { height: "0" },
},
"caret-blink": {
"0%,70%,100%": { opacity: "1" },
"20%,50%": { opacity: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
"collapsible-down": "collapsible-down 0.2s ease-out",
"collapsible-up": "collapsible-up 0.2s ease-out",
"caret-blink": "caret-blink 1.25s ease-out infinite",
},
},
},
plugins: [require("tailwindcss-animate")],
};
export default config;

View file

@ -1,22 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": [
"vite/client"
],
"noEmit": true,
"isolatedModules": true,
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
}
}
}

View file

@ -1,31 +0,0 @@
import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
// import devtools from 'solid-devtools/vite';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export default defineConfig({
plugins: [
/*
Uncomment the following line to enable solid-devtools.
For more info see https://github.com/thetarnav/solid-devtools/tree/main/packages/extension#readme
*/
// devtools(),
solidPlugin(),
],
server: {
host: "127.0.0.1",
port: 3000,
},
build: {
target: "esnext",
},
resolve: {
alias: {
"@": resolve(__dirname, "./src"),
},
},
});

View file

@ -6,7 +6,7 @@
module.exports = {
content: {
relative: true,
files: ["./clients/leptos/*.html", "./clients/leptos/src/**/*.rs"],
files: ["./client/*.html", "./client/src/**/*.rs"],
},
theme: {
extend: {},

2
test
View file

@ -1,3 +1,3 @@
#!/bin/sh
cargo watch -i clients -i tools -cx "run -p server -- $1 $2"
cargo watch -i client -i tools -cx "run -p server -- $1 $2"