cooking with sqlite

This commit is contained in:
2025-08-05 23:49:13 -04:00
parent 9277089e04
commit 2ce46088d5
13 changed files with 117 additions and 80 deletions

View File

@@ -10,4 +10,4 @@ build:
start:
sudo docker run -p $(PORT):3000 -t games
sudo docker run -p $(PORT):3000 -p 5555:5555 -t games

View File

@@ -1 +0,0 @@
../sources/Card_back_01.svg

View File

@@ -1 +0,0 @@
../sources/Vector-Cards-Version-3.2/FACES (BORDERED)/STANDARD BORDERED/Single Cards (One Per FIle)/

View File

@@ -3,10 +3,11 @@
"type": "module",
"version": "0.0.2",
"scripts": {
"dev": "concurrently 'vinxi dev' 'pnpm dlx prisma studio --browser none'",
"dev": "concurrently 'vinxi dev' 'pnpm run dbstudio'",
"build": "vinxi build",
"start": "vinxi start",
"sync_db": "concurrently 'pnpm dlx prisma generate' 'pnpm dlx prisma migrate dev'"
"start": "concurrently 'vinxi start' 'pnpm run dbstudio'",
"dbstudio": "pnpm dlx prisma studio --browser none",
"dbsync": "concurrently 'pnpm dlx prisma generate' 'pnpm dlx prisma migrate dev'"
},
"dependencies": {
"@prisma/client": "6.13.0",

1
public/views/back.svg Symbolic link
View File

@@ -0,0 +1 @@
../../assets/sources/Card_back_01.svg

1
public/views/cards Symbolic link
View File

@@ -0,0 +1 @@
../../assets/sources/Vector-Cards-Version-3.2/FACES (BORDERED)/STANDARD BORDERED/Single Cards (One Per FIle)/

View File

@@ -1,5 +1,5 @@
import { Component, createResource, JSX, Suspense } from "solid-js";
import { Card } from "../types/cards";
import { Card, newDeck } from "../types/cards";
import { Clickable, Stylable } from "./toolbox";
const cardToSvgFilename = (card: Card) => {
@@ -17,17 +17,6 @@ const cardToSvgFilename = (card: Card) => {
};
export default ((props) => {
const [svgPath] = createResource(() =>
props.face == "down"
? // @ts-ignore
import("~/../assets/views/back.svg")
: import(
`~/../assets/views/cards/${cardToSvgFilename(
props.card
)}.svg`
)
);
return (
<Suspense>
<img
@@ -39,7 +28,11 @@ export default ((props) => {
...props.style,
}}
width="100px"
src={svgPath()?.default}
src={
props.face == "down"
? "/views/back.svg"
: `/views/cards/${cardToSvgFilename(props.card)}.svg`
}
/>
</Suspense>
);

View File

@@ -1,42 +1,54 @@
import { createContext, JSX } from "solid-js";
import {
Accessor,
createContext,
createResource,
JSX,
Show,
Suspense,
} from "solid-js";
import Card from "./Card";
import Hand from "./Hand";
import Pile from "./Pile";
import { GameState, newDeck, shuffle, Hand as THand } from "../types/cards";
import { createStore, produce, SetStoreFunction, Store } from "solid-js/store";
import { getGameState, updateGameState } from "../db/Instances";
export const GameContext = createContext<{
gameState: Store<GameState>;
setGameState: SetStoreFunction<GameState>;
gameState: Accessor<GameState | undefined>;
setGameState: (state: GameState) => Promise<any>;
}>();
export default (props: { initialState: GameState }) => {
const [gameState, setGameState] = createStore<GameState>(
props.initialState
export default (props: { instanceId: number }) => {
const [gameState, { refetch }] = createResource(() =>
getGameState(props.instanceId)
);
const setGameState = (state: GameState) =>
updateGameState(props.instanceId, state).then(refetch);
return (
<GameContext.Provider value={{ gameState, setGameState }}>
<div
onClick={() => {}}
class="full column center"
style={{ "row-gap": "20px", "font-size": "32px" }}
>
<div class="full center">
<Pile
pile={gameState.deck}
style={{ cursor: "pointer" }}
onClick={() =>
setGameState(
produce((state) => {
state.hand.push(state.deck.pop()!);
})
)
}
/>
<Show when={gameState() != undefined}>
<div
onClick={() => {}}
class="full column center"
style={{ "row-gap": "20px", "font-size": "32px" }}
>
<div class="full center">
<Pile
pile={gameState()!.deck}
style={{ cursor: "pointer" }}
onClick={() => {
const [drawn, ...rest] = gameState()!.deck;
setGameState({
deck: rest,
hand: [drawn, ...gameState()!.hand],
});
}}
/>
</div>
<Hand hand={gameState()!.hand} />
</div>
<Hand hand={gameState.hand} />
</div>
</Show>
</GameContext.Provider>
);
};

View File

@@ -5,7 +5,7 @@ import { GameContext } from "./Game";
import { produce } from "solid-js/store";
export default ((props) => {
const { setGameState } = useContext(GameContext)!;
const { setGameState, gameState } = useContext(GameContext)!;
return (
<div
@@ -33,20 +33,16 @@ export default ((props) => {
style={{
cursor: "pointer",
}}
onClick={() =>
setGameState(
produce((state) => {
const index = state.hand.indexOf(card);
console.log(index);
state.deck.push(
state.hand.splice(
props.hand.indexOf(card),
1
)[0]!
);
})
)
}
onClick={() => {
const index = gameState()!.hand.indexOf(card);
setGameState({
deck: [card, ...gameState()!.deck],
hand: [
...gameState()!.hand.slice(0, index),
...gameState()!.hand.slice(index + 1),
],
});
}}
/>
)}
</For>

View File

@@ -1,6 +1,25 @@
"use server";
import { GameState, newDeck, shuffle } from "../types/cards";
import { prisma } from "./db";
export const queryInstances = async (gameName: string) =>
await prisma.instance.findMany({ where: { game: { name: gameName } } });
prisma.instance.findMany({ where: { game: { name: gameName } } });
export const createInstance = (gameName: string) =>
prisma.instance.create({
data: {
gameState: { deck: shuffle(newDeck()), hand: [] } as GameState,
game: { connect: { name: gameName } },
},
});
export const getGameState = (instanceId: number) =>
prisma.instance
.findUnique({ where: { id: instanceId } })
.then((i) => i?.gameState as GameState | undefined);
export const updateGameState = async (
instanceId: number,
gameState: GameState
) => prisma.instance.update({ where: { id: instanceId }, data: { gameState } });

View File

@@ -1,19 +1,30 @@
import { useParams } from "@solidjs/router";
import { A, useParams } from "@solidjs/router";
import { createEffect, createResource, Show, Suspense } from "solid-js";
import Game from "../../components/Game";
import { aql } from "arangojs";
import { getGameState } from "../../db/Instances";
export default () => {
const params = useParams();
const [instance] = createResource(async () => {
return null;
});
const params = useParams<{ game: string; instance: string }>();
return (
<Show when={instance() != null}>
<Game state={instance()!} />
</Show>
<>
<Game instanceId={Number.parseInt(params.instance)} />
<A
href={`/${params.game}`}
style={{
position: "absolute",
padding: "10px",
top: "0",
left: "0",
margin: "20px",
"background-color": "white",
"border-radius": "8px",
border: "2px solid black",
}}
>
Back
</A>
</>
);
};

View File

@@ -5,26 +5,31 @@ import * as Instance from "../../db/Instances";
export default () => {
const params = useParams<{ game: string }>();
createEffect(() => {
console.log(">>", params.game);
});
const [instances] = createResource(
const [instances, { refetch }] = createResource(
() => params.game,
() => Instance.queryInstances(params.game)
);
createEffect(() => console.log(instances()));
return (
<Suspense>
<div style={{ padding: "20px" }}>
<h1 style={{ margin: 0 }}>{params.game}</h1>
<button
onClick={() =>
Instance.createInstance(params.game).then(refetch)
}
>
New Game
</button>
<ul>
<For each={instances() ?? []}>
{(instance) => (
<A href={`/${params.game}/${instance._id}`}>
{instance._id}
</A>
<li>
<A href={`/${params.game}/${instance.id}`}>
{instance.id}
</A>
</li>
)}
</For>
</ul>

View File

@@ -1,6 +1,6 @@
import { A } from "@solidjs/router";
import { createResource, For } from "solid-js";
import * as Games from "../db/games";
import * as Games from "../db/Games";
export default () => {
const [games] = createResource(() => Games.queryAll());