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,
});
upsertGameState(db, newGame);
// Emit new game event with gameId for spectating
emit({
type: "new",
user,
gameId: uuid,
});
emit({
type: "updateStage",

View File

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

View File

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

View File

@ -24,12 +24,19 @@ const Feed: React.FC = () => {
const data = JSON.parse(event.data) as Events;
const newItems = [...items];
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",
user: data.user,
gameId: data.gameId,
id: crypto.randomUUID(),
decay: Date.now() + 1000 * 3,
});
setItems(filteredItems);
return;
}
if (data.type === "loss") {
newItems.push({

View File

@ -5,6 +5,7 @@ import GemsIcon from "../GemIcon";
import type { Rarity as RarityType } from "../../../shared/lootboxes";
import { Rarity } from "../Rarity";
import { themes } from "../../themes";
import { Link } from "wouter";
interface BaseFeedItem {
decay: number;
@ -14,6 +15,7 @@ interface BaseFeedItem {
interface GameStartedItem extends BaseFeedItem {
type: "gameStarted";
user: string;
gameId: string;
}
interface GameFinishedItem extends BaseFeedItem {
@ -59,7 +61,19 @@ const FeedItemWrapper: React.FC<PropsWithChildren> = ({ children }) => {
const FeedItemElement: React.FC<{ item: FeedItem }> = ({ item }) => {
switch (item.type) {
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":
return (
<FeedItemWrapper>

View File

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