use custom button component to rid all the css

This commit is contained in:
SamKry
2025-11-18 19:32:36 +01:00
parent a82037a698
commit f113ed6042
6 changed files with 79 additions and 45 deletions

View File

@@ -0,0 +1,13 @@
import { ButtonHTMLAttributes } from "react";
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
}
export function Button({ variant = "primary", className = "", ...props }: Readonly<ButtonProps>) {
const baseClasses = variant === "primary"
? "rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-50 disabled:cursor-not-allowed"
: "rounded bg-white px-2 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-white/10 dark:text-white dark:ring-0 dark:hover:bg-white/20";
return <button className={`${baseClasses} ${className}`} {...props} />;
}

View File

@@ -1,5 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import Web3 from "web3"; import Web3 from "web3";
import { Button } from "./Button";
import { Input } from "./Input";
interface CommitProps { interface CommitProps {
account: string; account: string;
@@ -64,28 +66,28 @@ export default function Commit({
return ( return (
<div className="border p-4 rounded-lg"> <div className="border p-4 rounded-lg">
<h2 className="font-semibold mb-2">play(bytes32 encrMove)</h2> <h2 className="font-semibold mb-2">play(bytes32 encrMove)</h2>
<input <Input
type="text" type="text"
placeholder="Encrypted Move (bytes32)" placeholder="Encrypted Move (bytes32)"
value={playMove} value={playMove}
onChange={(e) => setPlayMove(e.target.value)} onChange={(e) => setPlayMove(e.target.value)}
className="border px-2 py-1 mr-2 rounded" className="mr-2"
/> />
<button <Button
onClick={handlePlay} onClick={handlePlay}
disabled={loading || !account || !contract} disabled={loading || !account || !contract}
className="bg-blue-500 text-white px-4 py-2 rounded" variant="primary"
> >
Play Play
</button> </Button>
<div className="mt-4 space-y-2"> <div className="mt-4 space-y-2">
<button <Button
onClick={handleBothPlayed} onClick={handleBothPlayed}
className="bg-gray-200 px-2 py-1 rounded" variant="secondary"
> >
bothPlayed bothPlayed
</button> </Button>
<span className="ml-2 text-xs">{bothPlayed}</span> <span className="ml-2 text-xs">{bothPlayed}</span>
<br /> <br />
</div> </div>

View File

@@ -0,0 +1,9 @@
import { InputHTMLAttributes } from "react";
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {}
export function Input({ className = "", ...props }: Readonly<InputProps>) {
const baseClasses = "rounded-md border-0 px-3 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:bg-white/5 dark:ring-white/10 dark:focus:ring-indigo-500";
return <input className={`${baseClasses} ${className}`} {...props} />;
}

View File

@@ -1,5 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import Web3 from "web3"; import Web3 from "web3";
import { Button } from "./Button";
import { Input } from "./Input";
interface LobbyProps { interface LobbyProps {
account: string; account: string;
@@ -168,6 +170,7 @@ export default function Lobby({
setStatus("Register tx sent: " + result); setStatus("Register tx sent: " + result);
} catch (err: any) { } catch (err: any) {
setStatus("Register failed: " + err.message); setStatus("Register failed: " + err.message);
console.error(err);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@@ -175,59 +178,59 @@ export default function Lobby({
return ( return (
<div className="border p-4 rounded-lg"> <div className="border p-4 rounded-lg">
<h2 className="font-semibold mb-2">register(uint gameId) (payable)</h2> <h2 className="font-semibold mb-2">register(uint gameId) (payable)</h2>
<input <Input
type="text" type="text"
placeholder="Game ID (0 = auto)" placeholder="Game ID (0 = auto)"
value={registerGameId} value={registerGameId}
onChange={(e) => setRegisterGameId(e.target.value)} onChange={(e) => setRegisterGameId(e.target.value)}
className="border px-2 py-1 mr-2 rounded" className="mr-2"
/> />
<input <Input
type="number" type="number"
min="0.01" min="0.01"
step="0.01" step="0.01"
placeholder="Bet in ETH (default 0.01)" placeholder="Bet in ETH (default 0.01)"
value={registerBet} value={registerBet}
onChange={(e) => setRegisterBet(e.target.value)} onChange={(e) => setRegisterBet(e.target.value)}
className="border px-2 py-1 mr-2 rounded" className="mr-2"
/> />
<div className="text-xs text-slate-500 mt-1"> <div className="text-xs text-slate-500 dark:text-slate-400 mt-1">
Enter amount in ETH (e.g., 0.01 for 0.01 ETH). Entering 1 means 1 full Enter amount in ETH (e.g., 0.01 for 0.01 ETH). Entering 1 means 1 full
ETH. ETH.
</div> </div>
<button <Button
onClick={handleRegister} onClick={handleRegister}
disabled={loading || !account || !contract} disabled={loading || !account || !contract}
className="bg-blue-500 text-white px-4 py-2 rounded" variant="primary"
> >
Register Register
</button> </Button>
<div className="mt-4 space-y-2"> <div className="mt-4 space-y-2">
<button onClick={handleGetBetMin} className="bg-gray-200 px-2 py-1 rounded">BET_MIN</button> <Button onClick={handleGetBetMin} variant="secondary">BET_MIN</Button>
<span className="ml-2 text-xs">{betMin}</span> <span className="ml-2 text-xs">{betMin}</span>
<br /> <br />
<button onClick={handleGetActiveGameIds} className="bg-gray-200 px-2 py-1 rounded">getActiveGameIds</button> <Button onClick={handleGetActiveGameIds} variant="secondary">getActiveGameIds</Button>
<span className="ml-2 text-xs">{activeGameIds}</span> <span className="ml-2 text-xs">{activeGameIds}</span>
<br /> <br />
<button onClick={handleGetContractBalance} className="bg-gray-200 px-2 py-1 rounded">getContractBalance</button> <Button onClick={handleGetContractBalance} variant="secondary">getContractBalance</Button>
<span className="ml-2 text-xs">{contractBalance}</span> <span className="ml-2 text-xs">{contractBalance}</span>
<br /> <br />
<input type="text" placeholder="Game ID" value={gameDetailsId} onChange={e => setGameDetailsId(e.target.value)} className="border px-2 py-1 mr-2 rounded" /> <Input type="text" placeholder="Game ID" value={gameDetailsId} onChange={e => setGameDetailsId(e.target.value)} className="mr-2" />
<button onClick={handleGetGameDetails} className="bg-gray-200 px-2 py-1 rounded">getGameDetails</button> <Button onClick={handleGetGameDetails} variant="secondary">getGameDetails</Button>
<span className="ml-2 text-xs">{gameDetails && <pre className="inline whitespace-pre-wrap">{JSON.stringify(gameDetails, null, 2)}</pre>}</span> <span className="ml-2 text-xs">{gameDetails && <pre className="inline whitespace-pre-wrap">{JSON.stringify(gameDetails, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2)}</pre>}</span>
<br /> <br />
<button onClick={handleGetMyActiveGameId} className="bg-gray-200 px-2 py-1 rounded">getMyActiveGameId</button> <Button onClick={handleGetMyActiveGameId} variant="secondary">getMyActiveGameId</Button>
<span className="ml-2 text-xs">{myActiveGameId}</span> <span className="ml-2 text-xs">{myActiveGameId}</span>
<br /> <br />
<input type="text" placeholder="Past Game Index" value={pastGameIndex} onChange={e => setPastGameIndex(e.target.value)} className="border px-2 py-1 mr-2 rounded" /> <Input type="text" placeholder="Past Game Index" value={pastGameIndex} onChange={e => setPastGameIndex(e.target.value)} className="mr-2" />
<button onClick={handleGetPastGame} className="bg-gray-200 px-2 py-1 rounded">getPastGame</button> <Button onClick={handleGetPastGame} variant="secondary">getPastGame</Button>
<span className="ml-2 text-xs">{pastGame && <pre className="inline whitespace-pre-wrap">{JSON.stringify(pastGame, null, 2)}</pre>}</span> <span className="ml-2 text-xs">{pastGame && <pre className="inline whitespace-pre-wrap">{JSON.stringify(pastGame, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2)}</pre>}</span>
<br /> <br />
<button onClick={handleGetPastGamesCount} className="bg-gray-200 px-2 py-1 rounded">getPastGamesCount</button> <Button onClick={handleGetPastGamesCount} variant="secondary">getPastGamesCount</Button>
<span className="ml-2 text-xs">{pastGamesCount}</span> <span className="ml-2 text-xs">{pastGamesCount}</span>
<br /> <br />
<button onClick={handleWhoAmI} className="bg-gray-200 px-2 py-1 rounded">whoAmI</button> <Button onClick={handleWhoAmI} variant="secondary">whoAmI</Button>
<span className="ml-2 text-xs">{whoAmI}</span> <span className="ml-2 text-xs">{whoAmI}</span>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import Web3 from "web3"; import Web3 from "web3";
import { Button } from "./Button";
import { Input } from "./Input";
interface RevealProps { interface RevealProps {
account: string; account: string;
@@ -105,52 +107,52 @@ export default function Reveal({
return ( return (
<div className="border p-4 rounded-lg"> <div className="border p-4 rounded-lg">
<h2 className="font-semibold mb-2">reveal(string clearMove)</h2> <h2 className="font-semibold mb-2">reveal(string clearMove)</h2>
<input <Input
type="text" type="text"
placeholder="Clear Move (e.g. 1-password)" placeholder="Clear Move (e.g. 1-password)"
value={revealMove} value={revealMove}
onChange={(e) => setRevealMove(e.target.value)} onChange={(e) => setRevealMove(e.target.value)}
className="border px-2 py-1 mr-2 rounded" className="mr-2"
/> />
<button <Button
onClick={handleReveal} onClick={handleReveal}
disabled={loading || !account || !contract} disabled={loading || !account || !contract}
className="bg-blue-500 text-white px-4 py-2 rounded" variant="primary"
> >
Reveal Reveal
</button> </Button>
<div className="mt-4 space-y-2"> <div className="mt-4 space-y-2">
<button <Button
onClick={handleBothRevealed} onClick={handleBothRevealed}
className="bg-gray-200 px-2 py-1 rounded" variant="secondary"
> >
bothRevealed bothRevealed
</button> </Button>
<span className="ml-2 text-xs">{bothRevealed}</span> <span className="ml-2 text-xs">{bothRevealed}</span>
<br /> <br />
<button <Button
onClick={handlePlayerARevealed} onClick={handlePlayerARevealed}
className="bg-gray-200 px-2 py-1 rounded" variant="secondary"
> >
playerARevealed playerARevealed
</button> </Button>
<span className="ml-2 text-xs">{playerARevealed}</span> <span className="ml-2 text-xs">{playerARevealed}</span>
<br /> <br />
<button <Button
onClick={handlePlayerBRevealed} onClick={handlePlayerBRevealed}
className="bg-gray-200 px-2 py-1 rounded" variant="secondary"
> >
playerBRevealed playerBRevealed
</button> </Button>
<span className="ml-2 text-xs">{playerBRevealed}</span> <span className="ml-2 text-xs">{playerBRevealed}</span>
<br /> <br />
<button <Button
onClick={handleRevealTimeLeft} onClick={handleRevealTimeLeft}
className="bg-gray-200 px-2 py-1 rounded" variant="secondary"
> >
revealTimeLeft revealTimeLeft
</button> </Button>
<span className="ml-2 text-xs">{revealTimeLeft}</span> <span className="ml-2 text-xs">{revealTimeLeft}</span>
</div> </div>
</div> </div>

View File

@@ -16,6 +16,11 @@ export default function Clash() {
// Inputs for contract functions // Inputs for contract functions
const [phase, setPhase] = useState<"lobby" | "commit" | "reveal">("lobby"); const [phase, setPhase] = useState<"lobby" | "commit" | "reveal">("lobby");
// Clear status when phase changes
useEffect(() => {
setStatus("");
}, [phase]);
// Load config and contract // Load config and contract
useEffect(() => { useEffect(() => {
const loadConfig = async () => { const loadConfig = async () => {