diff --git a/package.json b/package.json index 634cee5..a0d6c8c 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,16 @@ "dependencies": { "@solidjs/router": "^0.15.3", "@solidjs/start": "^1.1.0", + "kefir": "^3.8.8", + "kefir-bus": "^2.3.1", + "lowdb": "^7.0.1", "solid-js": "^1.9.5", "vinxi": "^0.5.7" }, "engines": { "node": ">=22" + }, + "devDependencies": { + "@types/kefir": "^3.8.11" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 435a044..6efced4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,25 @@ importers: '@solidjs/start': specifier: ^1.1.0 version: 1.1.7(solid-js@1.9.7)(vinxi@0.5.8(@netlify/blobs@9.1.2)(@types/node@24.1.0)(db0@0.3.2)(ioredis@5.6.1)(jiti@2.5.1)(terser@5.43.1))(vite@6.3.5(@types/node@24.1.0)(jiti@2.5.1)(terser@5.43.1)) + kefir: + specifier: ^3.8.8 + version: 3.8.8 + kefir-bus: + specifier: ^2.3.1 + version: 2.3.1(kefir@3.8.8) + lowdb: + specifier: ^7.0.1 + version: 7.0.1 solid-js: specifier: ^1.9.5 version: 1.9.7 vinxi: specifier: ^0.5.7 version: 0.5.8(@netlify/blobs@9.1.2)(@types/node@24.1.0)(db0@0.3.2)(ioredis@5.6.1)(jiti@2.5.1)(terser@5.43.1) + devDependencies: + '@types/kefir': + specifier: ^3.8.11 + version: 3.8.11 packages: @@ -934,6 +947,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/kefir@3.8.11': + resolution: {integrity: sha512-5TRdFXQYsVUvqIH6nYjslHzBgn4hnptcutXnqAhfbKdWD/799c44hFhQGF3887E2t/Q4jSp3RvNFCaQ+b9w6vQ==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -2028,6 +2044,14 @@ packages: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} engines: {node: '>=18'} + kefir-bus@2.3.1: + resolution: {integrity: sha512-wLCQfEw8PddSNeyjDCH2WNgNg3Rb/c+OaG5WEPfEwod+LQfGX4isHcHRWsYNLmdFEw3/KyA+9qDSy+VC4NsifA==} + peerDependencies: + kefir: ^3.5.1 + + kefir@3.8.8: + resolution: {integrity: sha512-xWga7QCZsR2Wjy2vNL3Kq/irT+IwxwItEWycRRlT5yhqHZK2fmEhziP+LzcJBWSTAMranGKtGTQ6lFpyJS3+jA==} + kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -2082,6 +2106,10 @@ packages: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} engines: {node: '>= 12.0.0'} + lowdb@7.0.1: + resolution: {integrity: sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==} + engines: {node: '>=18'} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2743,6 +2771,10 @@ packages: std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + steno@4.0.2: + resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} + engines: {node: '>=18'} + streamx@2.22.1: resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} @@ -4083,6 +4115,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/kefir@3.8.11': + dependencies: + '@types/node': 24.1.0 + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -4094,7 +4130,6 @@ snapshots: '@types/node@24.1.0': dependencies: undici-types: 7.8.0 - optional: true '@types/normalize-package-data@2.4.4': {} @@ -5207,6 +5242,12 @@ snapshots: jwt-decode@4.0.0: {} + kefir-bus@2.3.1(kefir@3.8.8): + dependencies: + kefir: 3.8.8 + + kefir@3.8.8: {} + kleur@4.1.5: {} klona@2.0.6: {} @@ -5275,6 +5316,10 @@ snapshots: safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 + lowdb@7.0.1: + dependencies: + steno: 4.0.2 + lru-cache@10.4.3: {} lru-cache@5.1.1: @@ -6075,6 +6120,8 @@ snapshots: std-env@3.9.0: {} + steno@4.0.2: {} + streamx@2.22.1: dependencies: fast-fifo: 1.3.2 @@ -6220,8 +6267,7 @@ snapshots: undici-types@5.28.4: {} - undici-types@7.8.0: - optional: true + undici-types@7.8.0: {} unenv@1.10.0: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..012c404 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +onlyBuiltDependencies: + - '@parcel/watcher' + - esbuild diff --git a/src/app.css b/src/app.css index 22c43df..5cc6ebe 100644 --- a/src/app.css +++ b/src/app.css @@ -18,6 +18,13 @@ body::before { height: 100%; } +a { + color: rgb(18, 229, 113); +} +a:visited { + color: rgb(23, 138, 125); +} + #app { height: 100%; background: radial-gradient(rgb(24, 82, 65), rgb(1, 42, 16)); diff --git a/src/components/Game.tsx b/src/components/Game.tsx index c836cb1..c8e33b9 100644 --- a/src/components/Game.tsx +++ b/src/components/Game.tsx @@ -10,11 +10,10 @@ export const GameContext = createContext<{ setGameState: SetStoreFunction; }>(); -export default () => { - const [gameState, setGameState] = createStore({ - deck: shuffle(newDeck()), - hand: [], - }); +export default (props: { initialState: GameState }) => { + const [gameState, setGameState] = createStore( + props.initialState + ); return ( diff --git a/src/components/Hand.tsx b/src/components/Hand.tsx index 3ef62c2..0311eeb 100644 --- a/src/components/Hand.tsx +++ b/src/components/Hand.tsx @@ -19,7 +19,7 @@ export default ((props) => { margin: "10px", "margin-bottom": "25px", padding: "10px", - height: "200px", + height: "180px", overflow: "scroll", "scrollbar-width": "none", display: "flex", diff --git a/src/db.ts b/src/db.ts new file mode 100644 index 0000000..51b1044 --- /dev/null +++ b/src/db.ts @@ -0,0 +1,23 @@ +"use server"; +import { JSONFilePreset } from "lowdb/node"; +import { GameState, newGame } from "./types/cards"; + +type schema = { + games: { + [key: string]: { + name: string; + rules: string; + instances: { [id: string]: GameState }; + }; + }; +}; +const _db = await JSONFilePreset("db.json", { + games: { + renaissance: { + name: "renaissance", + rules: "", + instances: { test: newGame() }, + }, + }, +}); +export const db = async () => _db.read().then(() => _db.data); diff --git a/src/entry-server.tsx b/src/entry-server.tsx index 401eff8..7c0ed2b 100644 --- a/src/entry-server.tsx +++ b/src/entry-server.tsx @@ -1,21 +1,25 @@ // @refresh reload import { createHandler, StartServer } from "@solidjs/start/server"; +import { JSONFilePreset } from "lowdb/node"; export default createHandler(() => ( - ( - - - - - - {assets} - - -
{children}
- {scripts} - - - )} - /> + ( + + + + + + {assets} + + +
{children}
+ {scripts} + + + )} + /> )); diff --git a/src/routes/[game]/[instance].tsx b/src/routes/[game]/[instance].tsx new file mode 100644 index 0000000..28f9d7e --- /dev/null +++ b/src/routes/[game]/[instance].tsx @@ -0,0 +1,18 @@ +import { useParams } from "@solidjs/router"; +import { db } from "../../db"; +import { createEffect, createResource, Show, Suspense } from "solid-js"; +import Game from "../../components/Game"; + +export default () => { + const params = useParams(); + + const [instance] = createResource(() => + db().then((data) => data.games[params.game].instances[params.instance]) + ); + + return ( + + + + ); +}; diff --git a/src/routes/[game]/index.tsx b/src/routes/[game]/index.tsx new file mode 100644 index 0000000..e75e50c --- /dev/null +++ b/src/routes/[game]/index.tsx @@ -0,0 +1,37 @@ +import { A, useParams } from "@solidjs/router"; + +import { createEffect, createResource, For, Suspense } from "solid-js"; +import { db } from "../../db"; + +export default () => { + const params = useParams(); + createEffect(() => { + console.log(">>", params.game); + }); + const [instances] = createResource( + () => params.game, + () => + db().then((data) => { + if (params.game == null) { + return {}; + } + return data.games[params.game].instances; + }) + ); + return ( + +
+

{params.game}

+ +
+
+ ); +}; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 44dd1f0..cde83c8 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,5 +1,15 @@ +import { A } from "@solidjs/router"; import Game from "../components/Game"; +import { createResource, For } from "solid-js"; +import { db } from "../db"; export default () => { - return ; + const [games] = createResource(() => db().then((data) => data.games)); + return ( +
+ + {([gameId, game]) => {game.name}} + +
+ ); }; diff --git a/src/types/cards.ts b/src/types/cards.ts index 5b75a48..4f8c37f 100644 --- a/src/types/cards.ts +++ b/src/types/cards.ts @@ -60,3 +60,8 @@ export type GameState = { deck: Pile; hand: Hand; }; +export const newGame = () => + ({ + deck: shuffle(newDeck()), + hand: [], + } as GameState);