5const app = new Hono();
6
7// Game logic functions
8function checkWinner(board: (Player | null)[]): Player | null {
9 const winPatterns = [
10 [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows
22}
23
24function isBoardFull(board: (Player | null)[]): boolean {
25 return board.every(cell => cell !== null);
26}
3import type { GameState, Player, Board, GameStatus } from "../../shared/types.ts";
4
5export async function createGame(): Promise<GameState> {
6 const id = crypto.randomUUID();
7 const now = new Date().toISOString();
27}
28
29export async function getGame(id: string): Promise<GameState | null> {
30 const result = await sqlite.execute(
31 `SELECT * FROM ${TABLE_NAME} WHERE id = ?`,
49}
50
51export async function updateGame(game: GameState): Promise<void> {
52 const now = new Date().toISOString();
53
67}
68
69export async function getRecentGames(limit: number = 10): Promise<GameState[]> {
70 const result = await sqlite.execute(
71 `SELECT * FROM ${TABLE_NAME} ORDER BY updated_at DESC LIMIT ?`,
9}
10
11export default function GameStatus({ game, onNewGame, loading }: GameStatusProps) {
12 const getStatusMessage = () => {
13 if (game.status === 'won') {
9}
10
11export default function GameBoard({ game, onCellClick, disabled }: GameBoardProps) {
12 const renderCell = (position: number) => {
13 const value = game.board[position];
5import type { GameState, GameResponse, MoveRequest } from "../../shared/types.ts";
6
7export default function App() {
8 const [game, setGame] = useState<GameState | null>(null);
9 const [loading, setLoading] = useState(false);
3const TABLE_NAME = 'tic_tac_toe_games_1';
4
5export async function runMigrations() {
6 await sqlite.execute(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
7 id TEXT PRIMARY KEY,
7});
8
9function calculateAge() {
10 const currDate = Date.now();
11 const pastDate = Date.parse(dateInpElem.value);
6
7// token, user, and other opts are as specified at https://pushover.net/api
8export async function pushover({ message, title }) {
9 console.log("Input:", { message, title });
10 console.log("Tokens:", { PUSHOVER_TOKEN, PUSHOVER_USER_KEY }); // Check if env vars are set
11resetBtnElem.addEventListener("click", reset);
12
13function timer () {
14 counter += 1;
15
33}
34
35function start () {
36 interval = setInterval(timer, 1000);
37}
38
39function stop () {
40 clearInterval(interval);
41 interval = null;
42}
43
44function reset () {
45 stop();
46 counter = 0;
3import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
4
5function getCurrentWeekString() {
6 const now = new Date();
7 const monday = new Date(now);
14}
15
16function checkForNewWeek(savedData) {
17 if (!savedData) return null;
18
46}
47
48function ItemCard({ item, category, confirmItem, moveItem, removeItem }) {
49 return (
50 <div className={`card ${item.needsConfirmation ? 'needs-confirmation' : ''}`}>
158}
159
160function AddForm({ category, newItemText, setNewItemText, addItem, onCancel }) {
161 return (
162 <div className="new-card-form">
187}
188
189function App() {
190 const [data, setData] = useState({
191 working: [],
215 }, [data]);
216
217 function addItem(category, text) {
218 const newItem = {
219 id: Date.now(),
233 }
234
235 function confirmItem(category, itemId, action = 'stay') {
236 const item = data[category].find(item => item.id === itemId);
237 if (!item) return;
258 }
259
260 function moveItem(fromCategory, toCategory, itemId) {
261 const item = data[fromCategory].find(item => item.id === itemId);
262 if (!item) return;
269 }
270
271 function removeItem(category, itemId) {
272 if (!confirm('Remove this item permanently?')) return;
273
354}
355
356function client() {
357 createRoot(document.getElementById("root")).render(<App />);
358}
362}
363
364export default async function server(request: Request): Promise<Response> {
365 return new Response(`
366 <html>