added spectate button

This commit is contained in:
MasterGordon 2025-09-16 00:47:39 +02:00
parent 33c54983d4
commit 136612da24
6 changed files with 28 additions and 4 deletions

View File

@ -42,9 +42,11 @@ export const gameController = createController({
theme: pickRandom(collection.entries.filter((e) => e.selected)).id, theme: pickRandom(collection.entries.filter((e) => e.selected)).id,
}); });
upsertGameState(db, newGame); upsertGameState(db, newGame);
// Emit new game event with gameId for spectating
emit({ emit({
type: "new", type: "new",
user, user,
gameId: uuid,
}); });
emit({ emit({
type: "updateStage", type: "updateStage",

View File

@ -233,7 +233,7 @@ export const game = {
if (!isValid(serverGame, x, y)) return; if (!isValid(serverGame, x, y)) return;
if (isQuestionMark[x][y]) return; if (isQuestionMark[x][y]) return;
if (isFlagged[x][y]) return; if (isFlagged[x][y]) return;
serverGame.lastClick = [x, y]; if (initial) serverGame.lastClick = [x, y];
if (mines[x][y]) { if (mines[x][y]) {
serverGame.finished = Date.now(); serverGame.finished = Date.now();

View File

@ -6,6 +6,7 @@ export type Events =
| { | {
type: "new"; type: "new";
user: string; user: string;
gameId: string;
} }
| { | {
type: "loss"; type: "loss";

View File

@ -24,12 +24,19 @@ const Feed: React.FC = () => {
const data = JSON.parse(event.data) as Events; const data = JSON.parse(event.data) as Events;
const newItems = [...items]; const newItems = [...items];
if (data.type === "new" && data.user !== user) { if (data.type === "new" && data.user !== user) {
newItems.push({ // Remove any existing gameStarted items for this user
const filteredItems = newItems.filter(
item => !(item.type === "gameStarted" && item.user === data.user)
);
filteredItems.push({
type: "gameStarted", type: "gameStarted",
user: data.user, user: data.user,
gameId: data.gameId,
id: crypto.randomUUID(), id: crypto.randomUUID(),
decay: Date.now() + 1000 * 3, decay: Date.now() + 1000 * 3,
}); });
setItems(filteredItems);
return;
} }
if (data.type === "loss") { if (data.type === "loss") {
newItems.push({ newItems.push({

View File

@ -5,6 +5,7 @@ import GemsIcon from "../GemIcon";
import type { Rarity as RarityType } from "../../../shared/lootboxes"; import type { Rarity as RarityType } from "../../../shared/lootboxes";
import { Rarity } from "../Rarity"; import { Rarity } from "../Rarity";
import { themes } from "../../themes"; import { themes } from "../../themes";
import { Link } from "wouter";
interface BaseFeedItem { interface BaseFeedItem {
decay: number; decay: number;
@ -14,6 +15,7 @@ interface BaseFeedItem {
interface GameStartedItem extends BaseFeedItem { interface GameStartedItem extends BaseFeedItem {
type: "gameStarted"; type: "gameStarted";
user: string; user: string;
gameId: string;
} }
interface GameFinishedItem extends BaseFeedItem { interface GameFinishedItem extends BaseFeedItem {
@ -59,7 +61,19 @@ const FeedItemWrapper: React.FC<PropsWithChildren> = ({ children }) => {
const FeedItemElement: React.FC<{ item: FeedItem }> = ({ item }) => { const FeedItemElement: React.FC<{ item: FeedItem }> = ({ item }) => {
switch (item.type) { switch (item.type) {
case "gameStarted": case "gameStarted":
return <FeedItemWrapper>{item.user} started a game</FeedItemWrapper>; return (
<FeedItemWrapper>
<span>
{item.user} started a game -{" "}
<Link
href={`/play/${item.gameId}`}
className="text-white/70 hover:text-white/90 underline underline-offset-2 decoration-white/30 hover:decoration-white/50"
>
spectate
</Link>
</span>
</FeedItemWrapper>
);
case "gameFinished": case "gameFinished":
return ( return (
<FeedItemWrapper> <FeedItemWrapper>

View File

@ -73,7 +73,7 @@ const TouchTooltip = ({
}; };
interface ProfileProps { interface ProfileProps {
username?: string; username?: string | undefined;
} }
const Profile: React.FC<ProfileProps> = ({ username: targetUsername }) => { const Profile: React.FC<ProfileProps> = ({ username: targetUsername }) => {