Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions examples/ore-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@
"preview": "vite preview"
},
"dependencies": {
"hyperstack-react": "^0.5.0",
"hyperstack-stacks": "^0.5.0",
"@solana/wallet-adapter-phantom": "^0.9.24",
"@solana/wallet-adapter-react": "^0.15.39",
"@solana/wallet-adapter-react-ui": "^0.9.39",
"@solana/wallet-adapter-wallets": "^0.19.37",
"@solana/web3.js": "^1.98.4",
"buffer": "^6.0.3",
"hyperstack-react": "file:../../typescript/react",
"hyperstack-stacks": "file:../../stacks/sdk/typescript",
"hyperstack-typescript": "file:../../typescript/core",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"zod": "^3.23.0",
Expand All @@ -25,6 +32,7 @@
"postcss": "^8.5.6",
"tailwindcss": "^4.1.18",
"typescript": "^5.3.0",
"vite": "^5.0.0"
"vite": "^5.0.0",
"vite-plugin-node-polyfills": "^0.25.0"
}
}
31 changes: 26 additions & 5 deletions examples/ore-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import { OreDashboard } from './components';
import { HyperstackProvider } from 'hyperstack-react';
import { ThemeProvider } from './hooks/useTheme';
import { useMemo } from 'react';
import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets';
import '@solana/wallet-adapter-react-ui/styles.css';

export default function App() {
const endpoint = import.meta.env.VITE_RPC_URL; // add your own RPC URL in a .env file

// Setup wallet adapters
const wallets = useMemo(
() => [
new PhantomWalletAdapter(),
],
[]
);

return (
<ThemeProvider>
<HyperstackProvider autoConnect={true}>
<OreDashboard />
</HyperstackProvider>
</ThemeProvider>
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
<ThemeProvider>
<HyperstackProvider autoConnect={true}>
<OreDashboard />
</HyperstackProvider>
</ThemeProvider>
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
}
82 changes: 54 additions & 28 deletions examples/ore-react/src/components/BlockGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import { MinerIcon, SolanaIcon } from './icons';

interface BlockGridProps {
round: ValidatedOreRound | undefined;
selectedSquares: number[];
onSquareClick: (squareId: number) => void;
winnerSquare?: number | null;
myDeployedSquares?: number[];
}

export function BlockGrid({ round }: BlockGridProps) {
export function BlockGrid({ round, selectedSquares, onSquareClick, winnerSquare, myDeployedSquares = [] }: BlockGridProps) {
const blocks = round
? round.state.deployed_per_square_ui.map((deployedUi, i) => ({
id: i + 1,
index: i,
minerCount: round.state.count_per_square[i],
deployedUi,
isWinner: round.results?.winning_square === i,
}))
: Array.from({ length: 25 }, (_, i) => ({
id: i + 1,
index: i,
minerCount: 0,
deployedUi: 0,
isWinner: false,
}));

return (
Expand All @@ -28,32 +32,54 @@ export function BlockGrid({ round }: BlockGridProps) {
width: 'calc((100vh - 120px - 4 * 0.5rem) / 5 * 5 + 4 * 0.5rem)'
}}
>
{blocks.map((block) => (
<div
key={block.id}
style={{ aspectRatio: '1' }}
className={`
bg-white dark:bg-stone-800 rounded-2xl p-4 flex flex-col justify-between
transition-all duration-200 hover:shadow-md dark:hover:bg-stone-750
${block.isWinner
? 'bg-amber-50 dark:bg-amber-900/30 ring-2 ring-amber-400 shadow-lg'
: 'shadow-sm dark:shadow-none dark:ring-1 dark:ring-stone-700'
}
`}
>
<div className="flex justify-between items-start">
<span className="text-stone-400 dark:text-stone-500 text-sm font-medium">{block.id}</span>
<div className="flex items-center gap-1.5 text-stone-400 dark:text-stone-500">
<span className="text-sm">{block.minerCount}</span>
<MinerIcon />
{blocks.map((block) => {
const isWinner = winnerSquare === block.index;
const isDeployed = myDeployedSquares.includes(block.index);
const isSelected = selectedSquares.includes(block.id);

const squareClass = isDeployed
? 'bg-emerald-50 dark:bg-emerald-900/30 ring-2 ring-emerald-500 shadow-lg'
: isSelected
? 'bg-blue-50 dark:bg-blue-900/30 ring-2 ring-blue-500 shadow-lg'
: isWinner
? 'bg-amber-50/70 dark:bg-amber-900/20 shadow-sm dark:shadow-none dark:ring-1 dark:ring-amber-800/50'
: 'shadow-sm dark:shadow-none dark:ring-1 dark:ring-stone-700';

return (
<button
key={block.id}
onClick={() => onSquareClick(block.id)}
style={{ aspectRatio: '1' }}
className={`
relative bg-white dark:bg-stone-800 rounded-2xl p-4 flex flex-col justify-between
transition-all duration-200 hover:shadow-md dark:hover:bg-stone-700
cursor-pointer hover:scale-[1.02] active:scale-[0.98]
${squareClass}
`}
>
<div className="flex justify-between items-start">
<span className="text-stone-400 dark:text-stone-500 text-sm font-medium">{block.id}</span>
<div className="flex items-center gap-1.5 text-stone-400 dark:text-stone-500">
<span className="text-sm">{block.minerCount}</span>
<MinerIcon />
</div>
</div>
<div className="flex items-center gap-2 text-xl font-semibold text-stone-800 dark:text-stone-100">
<SolanaIcon size={18} />
<span>{Number(block.deployedUi).toFixed(4)}</span>
</div>
</div>
<div className="flex items-center gap-2 text-xl font-semibold text-stone-800 dark:text-stone-100">
<SolanaIcon size={18} />
<span>{Number(block.deployedUi).toFixed(4)}</span>
</div>
</div>
))}
{isWinner && (
<div className="absolute bottom-2 right-2 text-amber-400 text-sm leading-none opacity-80">👑</div>
)}
{isDeployed && (
<div className="absolute bottom-2 right-2 w-5 h-5 bg-emerald-500 text-white rounded-full flex items-center justify-center text-xs font-bold">✓</div>
)}
{!isDeployed && isSelected && (
<div className="absolute bottom-2 right-2 w-5 h-5 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-bold">✓</div>
)}
</button>
);
})}
</div>
);
}
Loading
Loading