basic shape
This commit is contained in:
45
packages/client/src/components/Card.tsx
Normal file
45
packages/client/src/components/Card.tsx
Normal 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
|
||||
>;
|
||||
54
packages/client/src/components/Game.tsx
Normal file
54
packages/client/src/components/Game.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
51
packages/client/src/components/Hand.tsx
Normal file
51
packages/client/src/components/Hand.tsx
Normal 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 }>;
|
||||
46
packages/client/src/components/Pile.tsx
Normal file
46
packages/client/src/components/Pile.tsx
Normal 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
|
||||
>;
|
||||
0
packages/client/src/components/Player.tsx
Normal file
0
packages/client/src/components/Player.tsx
Normal file
0
packages/client/src/components/Table.tsx
Normal file
0
packages/client/src/components/Table.tsx
Normal file
16
packages/client/src/components/toolbox.tsx
Normal file
16
packages/client/src/components/toolbox.tsx
Normal 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;
|
||||
};
|
||||
Reference in New Issue
Block a user