diff --git a/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite new file mode 100644 index 0000000..4ebf78c Binary files /dev/null and b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite differ diff --git a/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-shm b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-shm new file mode 100644 index 0000000..79b32e9 Binary files /dev/null and b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-shm differ diff --git a/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-wal b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-wal new file mode 100644 index 0000000..0e4d350 Binary files /dev/null and b/.partykit/state/party/-PartyKitDurable/9ac1723a854a77d3096a9717ff406f08e2ccc5117b4faec0dae467907fc9647b.sqlite-wal differ diff --git a/package-lock.json b/package-lock.json index fb097d7..bfd3d7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "vite-react-typescript-starter", "version": "0.0.0", "dependencies": { + "@clerk/clerk-react": "^5.38.1", "lucide-react": "^0.344.0", "partykit": "^0.0.115", "partysocket": "^1.1.4", @@ -347,6 +348,66 @@ "node": ">=6.9.0" } }, + "node_modules/@clerk/clerk-react": { + "version": "5.38.1", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.38.1.tgz", + "integrity": "sha512-IOn/Raet3jwkug8P/gLMe2nsw2wKllWGOGPFOAaaYxbXfIZ8MPngNv2/MMgVRF7cAX1UwrmU1PzrLNtBJ/EHPQ==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "^3.17.0", + "@clerk/types": "^4.72.0", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + } + }, + "node_modules/@clerk/shared": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.17.0.tgz", + "integrity": "sha512-eYbA0xmKG1DluFmdVykXiElgZGTpCruEyXmIBAwokpxypd5nOpDsS1xvEKwYvZieLTZkFz21Z3Y6HdDI5cPxBQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@clerk/types": "^4.72.0", + "dequal": "2.0.3", + "glob-to-regexp": "0.4.1", + "js-cookie": "3.0.5", + "std-env": "^3.9.0", + "swr": "2.3.4" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@clerk/types": { + "version": "4.72.0", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.72.0.tgz", + "integrity": "sha512-SEkgiQNeTstC0/mQjHCGBEyX0/ALyWAa5QZBBvVOok204r48MLipfIKsXQhyWE2Hk6FIo5WT6YyqD36jaxUEIw==", + "license": "MIT", + "dependencies": { + "csstype": "3.1.3" + }, + "engines": { + "node": ">=18.17.0" + } + }, "node_modules/@cloudflare/workerd-darwin-64": { "version": "1.20240718.0", "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240718.0.tgz", @@ -2040,8 +2101,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/data-uri-to-buffer": { "version": "2.0.2", @@ -2077,6 +2137,15 @@ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2963,6 +3032,15 @@ "jiti": "bin/jiti.js" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3963,6 +4041,12 @@ "get-source": "^2.0.12" } }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "license": "MIT" + }, "node_modules/stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", @@ -4139,6 +4223,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.4.tgz", + "integrity": "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/system-architecture": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", @@ -4387,6 +4484,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 206a948..854d7d9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@clerk/clerk-react": "^5.38.1", "lucide-react": "^0.344.0", "partykit": "^0.0.115", "partysocket": "^1.1.4", diff --git a/party/index.ts b/party/index.ts index 5caff74..183081a 100644 --- a/party/index.ts +++ b/party/index.ts @@ -1,3 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import type * as Party from 'partykit/server'; + interface GameState { totalClicks: number; users: Record; @@ -47,7 +50,7 @@ const MILESTONES = [ ]; export default class GameServer implements Party.Server { - constructor(readonly party: Party.Party) {} + constructor(readonly party: Party.Party) { } gameState: GameState = { totalClicks: 0, @@ -65,11 +68,11 @@ export default class GameServer implements Party.Server { autoClickInterval?: NodeJS.Timeout; - onConnect(conn: Party.Connection, ctx: Party.ConnectionContext) { + onConnect(conn: Party.Connection, _ctx: Party.ConnectionContext) { conn.send(JSON.stringify({ type: 'game-state', state: this.gameState })); } - onMessage(message: string, sender: Party.Connection) { + onMessage(message: string, _sender: Party.Connection) { const data = JSON.parse(message) as Message; switch (data.type) { @@ -100,9 +103,9 @@ export default class GameServer implements Party.Server { handleClick(data: ClickMessage) { const clickValue = this.gameState.clickMultiplier; - + this.gameState.totalClicks += clickValue; - + if (!this.gameState.users[data.userId]) { this.gameState.users[data.userId] = { name: data.userName, @@ -110,7 +113,7 @@ export default class GameServer implements Party.Server { lastSeen: Date.now() }; } - + this.gameState.users[data.userId].clicks += clickValue; this.gameState.users[data.userId].lastSeen = Date.now(); @@ -120,16 +123,16 @@ export default class GameServer implements Party.Server { handlePurchaseUpgrade(data: PurchaseUpgradeMessage) { const upgrade = UPGRADES[data.upgradeId as keyof typeof UPGRADES]; const currentUpgrade = this.gameState.upgrades[data.upgradeId]; - + if (!upgrade || !currentUpgrade) return; const userClicks = this.gameState.users[data.userId]?.clicks || 0; - + if (userClicks >= currentUpgrade.cost) { this.gameState.users[data.userId].clicks -= currentUpgrade.cost; currentUpgrade.owned += 1; currentUpgrade.cost = Math.floor(upgrade.baseCost * Math.pow(upgrade.multiplier, currentUpgrade.owned)); - + this.updateGameMultipliers(); } } @@ -140,10 +143,10 @@ export default class GameServer implements Party.Server { Object.entries(this.gameState.upgrades).forEach(([upgradeId, upgrade]) => { const config = UPGRADES[upgradeId as keyof typeof UPGRADES]; - if (config.clickBonus) { + if ('clickBonus' in config && config.clickBonus) { this.gameState.clickMultiplier += config.clickBonus * upgrade.owned; } - if (config.autoClickRate) { + if ('autoClickRate' in config && config.autoClickRate) { this.gameState.autoClickRate += config.autoClickRate * upgrade.owned; } }); @@ -180,4 +183,4 @@ export default class GameServer implements Party.Server { } } -GameServer satisfies Party.Worker; \ No newline at end of file +GameServer satisfies Party.Worker; diff --git a/src/App.tsx b/src/App.tsx index cecc451..0448150 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { usePartyKit } from './hooks/usePartyKit'; import { ClickButton } from './components/ClickButton'; import { Counter } from './components/Counter'; @@ -7,6 +7,7 @@ import { Milestones } from './components/Milestones'; import { Leaderboard } from './components/Leaderboard'; import { Background } from './components/Background'; import { MILESTONES } from './config/milestones'; +import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/clerk-react'; function App() { const { gameState, sendClick, purchaseUpgrade, userId } = usePartyKit(); @@ -50,6 +51,13 @@ function App() {
+ {/* User Button */} +
+ + + +
+ {/* Celebration Message */} {celebrationMessage && (
@@ -125,8 +133,22 @@ function App() {
))}
+ {/* If not logged in, show popup overlaying the game to login */} + +
+
+

Welcome to Bozo Clicker!

+

Please sign in to start clicking!

+ + + +
+
+
); } -export default App; \ No newline at end of file +export default App; diff --git a/src/hooks/usePartyKit.ts b/src/hooks/usePartyKit.ts index a60438c..d3562b4 100644 --- a/src/hooks/usePartyKit.ts +++ b/src/hooks/usePartyKit.ts @@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react'; import PartySocket from 'partysocket'; import { GameState } from '../types'; -const PARTY_HOST = import.meta.env.DEV ? 'localhost:1998' : 'bozo-clicker.your-username.partykit.dev'; +const PARTY_HOST = import.meta.env.DEV ? 'localhost:1999' : 'bozo-clicker.your-username.partykit.dev'; export function usePartyKit() { const [gameState, setGameState] = useState(null); diff --git a/src/main.tsx b/src/main.tsx index ea9e363..ddfcddc 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,9 +2,18 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App.tsx'; import './index.css'; +import { ClerkProvider } from '@clerk/clerk-react' +// Import your Publishable Key +const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY + +if (!PUBLISHABLE_KEY) { + throw new Error('Missing Publishable Key') +} createRoot(document.getElementById('root')!).render( + + ); diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..8df78a0 --- /dev/null +++ b/todo.md @@ -0,0 +1,12 @@ +Basically add things from + +thewre should be an news section available as redeemable using clicks with fun news titles + +Dylan the Diabolical Dutchman +[BOZO] + — 00:00 +Like, at first it's only a bozo you click, after a while, codebugs pop up as bonuses, later, you can combo codebugs and shoominions as they pop up. Later, you get a mascot storm, where mascots of all types fly over the screen from left to right, and you have to click as many as possible. + +And some more + +Auth integration not completed with clerk, needs partykit to be integrated with clerk