This commit is contained in:
2025-09-01 22:53:57 -04:00
parent b433a26fc6
commit fd342e7d47
24 changed files with 132 additions and 332 deletions

View File

@@ -1,17 +1,14 @@
import { makePersisted } from "@solid-primitives/storage";
import { Route, Router } from "@solidjs/router";
import { createResource, lazy, Suspense } from "solid-js";
import pkg from "^/package.json";
import { createSignal, lazy, Suspense } from "solid-js";
import { render } from "solid-js/web";
import "virtual:uno.css";
import pkg from "^/package.json";
import "./style.css";
import api from "./api";
import { mePromise } from "./profile";
import { name, setName } from "./profile";
const Profile = () => {
let dialogRef!: HTMLDialogElement;
const [profile] = createResource(() =>
mePromise.then(() => api.profile.get())
);
return (
<>
@@ -24,10 +21,10 @@ const Profile = () => {
<div class="fixed tr bg-emerald-100 m-2 p-4 rounded-xl border-2 shadow-md shadow-black">
Name:{" "}
<input
value={profile()?.data?.name ?? ""}
value={name()}
onChange={(e) => {
dialogRef.close();
void api.setName.post({ name: e.target.value });
setName(e.target.value);
}}
class="bg-emerald-200 border-1.5 rounded-full px-4"
/>

View File

@@ -4,7 +4,7 @@ import type {
SimplePlayerView,
SimpleResult,
} from "@games/shared/games/simple";
import { me, profile } from "~/profile";
import { me } from "~/profile";
import Hand from "./Hand";
import Pile from "./Pile";
import { TableContext } from "./Table";
@@ -39,7 +39,7 @@ export default () => {
<span class="font-bold">
{view().playerTurn == me()
? "your"
: profile(view().playerTurn)()?.name + "'s"}
: table.playerNames[view().playerTurn] + "'s"}
</span>{" "}
turn
</div>

View File

@@ -1,5 +1,5 @@
import { createSignal, useContext } from "solid-js";
import { playerColor, profile } from "~/profile";
import { playerColor } from "~/profile";
import { TableContext } from "./Table";
import { Stylable } from "./toolbox";
import { createObservable, createObservableWithInit } from "~/fn";
@@ -31,7 +31,7 @@ export default (props: { playerKey: string } & Stylable) => {
class={`${props.class} w-20 h-20 rounded-full flex justify-center items-center`}
>
<p style={{ "font-size": "1em" }}>
{profile(props.playerKey)()?.name}
{table?.playerNames[props.playerKey]}
</p>
</div>
);

View File

@@ -10,16 +10,24 @@ import {
Show,
} from "solid-js";
import api, { fromWebsocket } from "~/api";
import { createObservable, createObservableWithInit, cx } from "~/fn";
import { me, mePromise, profile } from "~/profile";
import {
createObservable,
createObservableStore,
createObservableWithInit,
cx,
} from "~/fn";
import { me, mePromise } from "~/profile";
import Game from "./Game";
import Player from "./Player";
import games from "@games/shared/games/index";
import { createStore, Store } from "solid-js/store";
import { name } from "~/profile";
export const TableContext = createContext<{
view: Accessor<any>;
sendWs: (msg: TWsIn) => void;
wsEvents: Stream<TWsOut, any>;
playerNames: Store<{ [key: string]: string }>;
}>();
export default (props: { tableKey: string }) => {
@@ -37,7 +45,9 @@ export default (props: { tableKey: string }) => {
);
onCleanup(() => wsPromise.then((ws) => ws.close()));
const presenceEvents = wsEvents.filter((evt) => evt.playersPresent != null);
const presenceEvents = wsEvents.filter(
(evt) => evt.playersPresent !== undefined
);
const gameEvents = wsEvents.filter((evt) => evt.view !== undefined);
const resultEvents = wsEvents.filter((evt) => evt.results !== undefined);
@@ -45,6 +55,13 @@ export default (props: { tableKey: string }) => {
presenceEvents.map((evt) => evt.playersPresent!),
[]
);
const playerNames = createObservableStore(
wsEvents
.filter((evt) => evt.playerNames != null)
.map(({ playerNames }) => playerNames!)
.toProperty(),
{}
);
const [ready, setReady] = createSignal(false);
mePromise.then(
@@ -57,8 +74,9 @@ export default (props: { tableKey: string }) => {
);
createEffect(() => sendWs({ ready: ready() }));
createEffect(() => sendWs({ name: name() }));
const view = createObservable(gameEvents.map((evt) => evt.view));
const results = createObservable(
const results = createObservable<string>(
merge([
gameEvents
.filter((evt) => "view" in evt && evt.view == null)
@@ -73,6 +91,7 @@ export default (props: { tableKey: string }) => {
sendWs,
wsEvents,
view,
playerNames,
}}
>
<div class="flex justify-around p-t-14">
@@ -138,7 +157,7 @@ export default (props: { tableKey: string }) => {
</Show>
<Show when={results() != null}>
<span class="bg-[var(--light)] text-[var(--dark)] rounded-[24px] border-2 border-[var(--dark)] absolute center p-4 shadow-lg text-[4em] text-center">
{profile(results())()?.name} won!
{playerNames[results()!]} won!
</span>
</Show>
</TableContext.Provider>

View File

@@ -1,5 +1,6 @@
import { Observable } from "kefir";
import { Accessor, createSignal } from "solid-js";
import { createStore } from "solid-js/store";
declare global {
interface Array<T> {
@@ -37,3 +38,12 @@ export const createObservableWithInit = <T>(
};
export const cx = (...classes: string[]) => classes.join(" ");
export const createObservableStore = <T extends object = {}>(
obs: Observable<T, any>,
init: T
) => {
const [store, setStore] = createStore<T>(init);
obs.onValue((val) => setStore(val));
return store;
};

View File

@@ -1,26 +1,16 @@
import { createResource, Resource } from "solid-js";
import { createEffect, createResource, createSignal, Resource } from "solid-js";
import { ApiType } from "./fn";
import api from "./api";
import hash from "object-hash";
import { makePersisted } from "@solid-primitives/storage";
export const mePromise = api.whoami.post().then((r) => r.data);
export const [me] = createResource(() => mePromise);
const playerProfiles: {
[humanKey: string]: Resource<ApiType<typeof api.profile.get>>;
} = {};
export const profile = (humanKey: string) => {
if (!(humanKey in playerProfiles)) {
playerProfiles[humanKey] = createResource(() =>
api.profile
.get({ query: { otherHumanKey: humanKey } })
.then((r) => r.data)
)[0];
}
return playerProfiles[humanKey];
};
createEffect(() => console.log(me()));
export const playerColor = (humanKey: string) =>
"#" + hash(humanKey).substring(0, 6);
export const [name, setName] = makePersisted(createSignal("__name__"), {
name: "name",
});