basic shape

This commit is contained in:
2025-08-06 23:29:55 -04:00
parent 3891e8b85b
commit 839d596b55
46 changed files with 220 additions and 5507 deletions

View File

@@ -0,0 +1,45 @@
import { Component, createResource, JSX, Suspense } from "solid-js";
import { Card, newDeck } from "../types/cards";
import { Clickable, Stylable } from "./toolbox";
const cardToSvgFilename = (card: Card) => {
if (card.kind == "joker") {
return `JOKER-${card.color == "black" ? "2" : "3"}`;
}
const value =
{ ace: 1, jack: 11, queen: 12, king: 13 }[
card.rank as "ace" | "jack" | "queen" | "king" // fuck you typescript
] ?? (card.rank as number);
return `${card.suit.toUpperCase()}-${value}${
value >= 11 ? "-" + (card.rank as string).toUpperCase() : ""
}`;
};
export default ((props) => {
return (
<Suspense>
<img
onClick={props.onClick}
draggable={false}
class={props.class}
style={{
"border-radius": "5px",
...props.style,
}}
width="100px"
src={
props.face == "down"
? "/views/back.svg"
: `/views/cards/${cardToSvgFilename(props.card)}.svg`
}
/>
</Suspense>
);
}) satisfies Component<
{
card: Card;
face?: "up" | "down";
} & Stylable &
Clickable
>;

View File

@@ -0,0 +1,54 @@
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: Accessor<GameState | undefined>;
setGameState: (state: GameState) => Promise<any>;
}>();
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 }}>
<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>
</Show>
</GameContext.Provider>
);
};

View File

@@ -0,0 +1,51 @@
import { Component, For, useContext } from "solid-js";
import Card from "./Card";
import { Hand } from "../types/cards";
import { GameContext } from "./Game";
import { produce } from "solid-js/store";
export default ((props) => {
const { setGameState, gameState } = useContext(GameContext)!;
return (
<div
class="hand"
style={{
"min-width": "100px",
width: "fit-content",
"max-width": "80%",
border: "2px dashed white",
"border-radius": "12px",
margin: "10px",
"margin-bottom": "25px",
padding: "10px",
height: "180px",
overflow: "scroll",
"scrollbar-width": "none",
display: "flex",
gap: "5px",
}}
>
<For each={props.hand}>
{(card) => (
<Card
card={card}
style={{
cursor: "pointer",
}}
onClick={() => {
const index = gameState()!.hand.indexOf(card);
setGameState({
deck: [card, ...gameState()!.deck],
hand: [
...gameState()!.hand.slice(0, index),
...gameState()!.hand.slice(index + 1),
],
});
}}
/>
)}
</For>
</div>
);
}) satisfies Component<{ hand: Hand }>;

View File

@@ -0,0 +1,46 @@
import { Component, For, JSX } from "solid-js";
import Card from "./Card";
import { Pile } from "../types/cards";
import { type ComponentProps } from "solid-js";
import { Clickable, Stylable } from "./toolbox";
export default ((props) => {
return (
<div
{...props}
class={`center ${props.class ?? ""}}`.trim()}
style={{
width: "200px",
height: "400px",
...(props.style as JSX.CSSProperties),
}}
onClick={props.onClick}
>
<For each={props.pile}>
{(card, i) => (
<Card
card={card}
face="down"
style={{
position: "absolute",
transform: `translate(${i() * 0.5}px, ${
i() * 0.2
}px)`,
// "z-index": 100 - i(),
border: `0.1px solid rgb(${
10 + i() + Math.random() * 50
}, ${10 + i() + Math.random() * 50}, ${
10 + i() + Math.random() * 50
});`,
}}
/>
)}
</For>
</div>
);
}) satisfies Component<
{
pile: Pile;
} & Stylable &
Clickable
>;

View File

View File

@@ -0,0 +1,16 @@
import { JSX } from "solid-js";
export type Stylable = {
class?: string;
style?: JSX.CSSProperties;
};
export type Clickable = {
onClick?:
| JSX.EventHandlerUnion<
HTMLDivElement,
MouseEvent,
JSX.EventHandler<HTMLDivElement, MouseEvent>
>
| undefined;
};