add WIP solid client
|
@ -1,6 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["server", "client", "lib", "tools/socket_blaster"]
|
members = ["server", "clients/leptos", "lib", "tools/socket_blaster"]
|
||||||
default-members = ["server", "lib"]
|
default-members = ["server", "lib"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "client/index.html"
|
target = "clients/leptos/index.html"
|
||||||
dist = "dist"
|
dist = "dist"
|
||||||
minify = "on_release"
|
minify = "on_release"
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
2
clients/solid/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
dist
|
34
clients/solid/README.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
## 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.)
|
16
clients/solid/components.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"$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"
|
||||||
|
}
|
||||||
|
}
|
22
clients/solid/index.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<!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>
|
34
clients/solid/package.json
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"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.7.5",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"postcss": "^8.4.47",
|
||||||
|
"solid-devtools": "^0.29.3",
|
||||||
|
"tailwindcss": "^3.4.14",
|
||||||
|
"typescript": "^5.6.3",
|
||||||
|
"vite": "^5.4.9",
|
||||||
|
"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",
|
||||||
|
"solid-js": "^1.9.2",
|
||||||
|
"tailwind-merge": "^2.5.4",
|
||||||
|
"tailwindcss-animate": "^1.0.7"
|
||||||
|
}
|
||||||
|
}
|
2623
clients/solid/pnpm-lock.yaml
generated
Normal file
7
clients/solid/postcss.config.cjs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
BIN
clients/solid/public/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
clients/solid/public/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
clients/solid/public/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
clients/solid/public/favicon-16x16.png
Normal file
After Width: | Height: | Size: 685 B |
BIN
clients/solid/public/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
clients/solid/public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
clients/solid/public/fonts/Inter-normal-400-cyrillic-ext.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-cyrillic.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-greek-ext.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-greek.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-latin-ext.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-latin.woff2
Normal file
BIN
clients/solid/public/fonts/Inter-normal-400-vietnamese.woff2
Normal file
1
clients/solid/public/site.webmanifest
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"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"}
|
50
clients/solid/src/App.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import type { JSXElement } from "solid-js";
|
||||||
|
import { ColorModeProvider, ColorModeScript } from "@kobalte/core";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsContent,
|
||||||
|
TabsIndicator,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "@/components/ui/tabs";
|
||||||
|
import Home from "@/pages/Home";
|
||||||
|
import Browser from "@/pages/Browser";
|
||||||
|
import Game from "@/pages/Game";
|
||||||
|
import Footer from "@/components/Footer";
|
||||||
|
|
||||||
|
export default function App(): JSXElement {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ColorModeScript />
|
||||||
|
<ColorModeProvider>
|
||||||
|
<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>
|
||||||
|
</ColorModeProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
5
clients/solid/src/components/Chat.tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { JSXElement } from "solid-js";
|
||||||
|
|
||||||
|
export function Chat(): JSXElement {
|
||||||
|
return <>chat</>;
|
||||||
|
}
|
5
clients/solid/src/components/Debug.tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { JSXElement } from "solid-js";
|
||||||
|
|
||||||
|
export function Debug(): JSXElement {
|
||||||
|
return <>debug</>;
|
||||||
|
}
|
58
clients/solid/src/components/Footer.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
66
clients/solid/src/components/ui/button.tsx
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
128
clients/solid/src/components/ui/dialog.tsx
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
107
clients/solid/src/components/ui/drawer.tsx
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
65
clients/solid/src/components/ui/popover.tsx
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
26
clients/solid/src/components/ui/separator.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
133
clients/solid/src/components/ui/tabs.tsx
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
158
clients/solid/src/index.css
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
@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;
|
||||||
|
}
|
14
clients/solid/src/index.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* @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!);
|
5
clients/solid/src/libs/cn.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import type { ClassValue } from "clsx";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export const cn = (...classLists: ClassValue[]) => twMerge(clsx(classLists));
|
9
clients/solid/src/pages/Browser.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import type { JSXElement } from "solid-js";
|
||||||
|
|
||||||
|
export default function Browser(): JSXElement {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
browser
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
5
clients/solid/src/pages/Game.tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import type { JSXElement } from "solid-js";
|
||||||
|
|
||||||
|
export default function Game(): JSXElement {
|
||||||
|
return <>game</>;
|
||||||
|
}
|
28
clients/solid/src/pages/Home.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
93
clients/solid/tailwind.config.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
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;
|
22
clients/solid/tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"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/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
clients/solid/vite.config.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
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: {
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
target: "esnext",
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": resolve(__dirname, "./src"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -6,7 +6,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: {
|
content: {
|
||||||
relative: true,
|
relative: true,
|
||||||
files: ["./client/*.html", "./client/src/**/*.rs"],
|
files: ["./clients/leptos/*.html", "./clients/leptos/src/**/*.rs"],
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
|
|